19
Fri, Apr
5 New Articles

Synchronization Issues with Java Servlets

Java
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

A servlet is Java program that executes in a Java-enabled Web server. It runs entirely within the Java Virtual Machine (JVM), and its purpose is to service requests from Web clients. The Web server then returns a response, typically in HTML, to the client. Servlets are a powerful way to replace Common Gateway Interface (CGI) programs written in various languages, such as C and Perl. Why use servlets? Consider the following reasons:

• Portability—Servlets are developed in Java, so you can move them to various operating systems without having to recompile the source code, as is the case with CGI modules.

• Efficiency—Servlets are loaded only once by the Web server. Each new request calls one of the servlet’s service methods, whereas a new CGI program is loaded for each client request.

• Persistence—Servlets, once loaded by the Web server, reside in memory, allowing a state to be maintained between requests. (An example of this is the “shopping cart” that is found on many Web sites.)

• Security—Servlets run on the server in a Java “sandbox,” which prevents them from disrupting the operating system or breaching security. They can also take advantage of the Java Security Manager architecture.

Servlets are also robust and extensible, because they are developed in an object- oriented language.

The Servlet Architecture

The servlet architecture consists of two java packages: javax.servlet and javax.servlet.http. The javax.servlet package contains interfaces (classes that define methods but do not implement them) and classes that are extended and implemented by all servlets. The javax.servlet.http package contains classes that are extended by servlets that will handle


HTTP requests. Central to the servlet architecture is the javax.servlet.Servlet interface class found in the javax.servlet package. Servlets implement the methods within this class to handle communication with Web clients.

There are three methods that are most important: init, service, and destroy. The init method is called once by the Web server when loading the servlet. (The init method typically establishes database connections.) The service method receives, handles, and responds to client requests. The destroy method performs cleanup functions (such as closing open database connections or files and terminating long-running threads) when the servlet is explicitly unloaded or the Web server is shut down.

The SimpleServlet class, shown in Figure 1 (page 76), is an example of the most basic of Java servlets; it has the init, service, and destroy methods. SimpleServlet merely responds to a Web-browsing client, via HTML, with the message “HELLO WORLD!”

The Servlet Environment

Once initialized and loaded by the Web server, a servlet resides in memory, ready to handle client requests. The Web server calls the servlet’s service method to handle these client requests. For example, the following URL request entered on a browser will be routed to SimpleServlet:

http://someHost/server/SimpleServlet

(Note that a servlet may also be called from an HTML form.) To communicate with the servlet, the Web server passes two objects to the service method: an HttpServletRequest, which encapsulates communication from the client to the server, and an HttpServletResponse, which encapsulates the communication from the servlet back to the client. HttpServletRequest and HttpServletResponse are interfaces defined by the javax.servlet package.

Request Processing and Concurrency Problems

As I stated, only one instance of SimpleServlet will be initialized and loaded by the Web server. As shown in Figure 2, if several clients are accessing the Web server, the servlet’s service method will be called by the Web server to handle the multiple clients. Technically, the servlet is running as a thread within the context of the Web server’s JVM. The resulting implication is that the calling clients will share the servlet’s resources, such as its instance variables, database connections, or external files.

For example, in Figure 3 (with the import statements and the init and destroy methods omitted for space), SimpleServlet is rewritten so that the service method saves the request object in the local variable clientRequest and then calls the displayWelcomMessage() method, whose purpose is to display the client’s user name on the browser. The client’s user name and password are retrieved from the clientRequest and stored in the username and password String variables before a response is made to the client with a welcome message.

All client calls will, however, share these variables, including the class variable clientRequest. But, when a simple servlet is written this way, there is no telling what each client will see on the browser; client 1 may see the user name from client 3 or client 2, which is unexpected behavior. Therefore, when developing servlets, you need to examine what might happen if multiple calls are made to the service method simultaneously. Specifically, examine what happens to servlet instance variables and how external resources are accessed in the service method.

Servlet Variables

A servlet’s instance variables (i.e., variables defined outside the scope of a method) maintain a client-specific state. For example, in Figure 3, the username and password


variables of SimpleServlet hold the calling client’s input. The danger here is that the values of these class variables may end up in an unknown state. Consider the following scenario. Client 1 calls the SimpleServlet’s service method, sets the clientRequest variable, and is preempted. Client 2 also calls SimpleServlet and sets clientRequest.

Meanwhile, client 1 is back and continues to execute the displayWelcomMessage() method. The problem in this scenario is that, because the clients share the same instance variable, clientRequest, the values of username and password displayed for client 1 are those sent by client 2.

There are several solutions to this problem. The first solution is to avoid declaring servlet variables at the instance level by either passing objects from method to method or declaring variables local to a method. In Figure 4, for example, the clientRequest variable has been eliminated, and the username and password variables are local to the displayWelcomMessage() method.

The second solution is to develop the servlet so that it handles only one client request at a time. This solution is achieved by implementing the SingleThreadModel as well as extending the HttpServlet class, as shown in Figure 5. With this implementation, each service call is handled serially by the Web server (i.e., the server makes sure that your servlet runs only one service method at a time). However, for the purpose of scalability and performance, the Web server should be capable of spawning new instances of the servlet as well as supporting some kind of pooling mechanism to prevent blocked access to the servlet. The user may, otherwise, experience a degraded performance. If the servlet were to access external resources, however, there would still be the issue of handling concurrency problems (which I’ll discuss in this article).

The third solution is to use Java threads and synchronize the methods or the specific block of code that is subject to concurrency problems. Java threads and synchronization may be new concepts to you, so let me explain them.

Accessing External Resources

Typical external resources include files, data structures, and databases that are accessed from the servlet via Java Database Connectivity (JDBC) or via Java Toolbox for AS/400’s record-level access classes. (Note that the database connections are instance fields and are typically constructed in the init method.)

A single client should not monopolize a resource that it is not actively using. When a client acquires a resource and blocks that resource while awaiting another resource (such as I/O), Java will allow a second client to access the resource. This condition makes sense and is often desirable. However, the flow of events must be taken into account, since the first client may not be done with its task and the second client may want to access the same resources, leading to a deadlock.

Accessing external resources typically involves reading and writing to the resources
(i.e., any number of threads should execute read operations simultaneously but allow only one thread to write or to modify the resource at a time). For example, with SimpleServlet, you may want to add code to validate the user name and password in the database as well as log the date and time of the last access. This is done by adding the following methods to SimpleServlet:

public synchronized boolean ValidateUsernameAndPassword(...)
public synchronized void UpdateLoginDatetime(...)

With this approach, the database read and write operations of the validate and update methods are synchronized by including the keyword synchronized in their method declarations. The existence of the keyword synchronized creates a lock for each instance of the class. A thread that calls a synchronized method belonging to the object instance must obtain this lock and automatically release it upon exiting. Any thread that attempts to


execute ValidateUsernameAndPassword() or UpdateLoginDatetime() is forced to wait until the lock becomes available. This effectively serializes all operations on the database; however, there is no scalability with this approach, and it results in very poor performance if the number of clients grows too large.

Instead of synchronizing an entire method, you can synchronize blocks of code within the methods that modify the resource. In the example shown in Figure 6, the code within the synchronized block can be executed only a single thread at a time. When each thread enters the synchronized section, it obtains a lock for the object, or instance, represented by this. Again, this technique ensures that only one process can use the update and read operations at a given time. In addition, “starvation” may occur, whereby a runaway thread monopolizes the resource within the modify block, effectively causing all other modify threads to block or wait indefinitely.

Synchronizing sections of code in a class, however, does not prevent simultaneous reading from and writing to a resource. Two different instances of a class will have independent locks, each of which can be obtained by two separate threads. In one instance, a thread may obtain a lock upon entering a synchronized update section of code, while, in the second instance, another thread obtains a lock upon entering the read section. This may lead to unexpected results, such as data corruption.

Implementing the Wait and Notify Methods

The wait and notify methods in conjunction with synchronization allow for the controlled acquisition and release of a lock. The wait method allows a thread to release its lock, to put itself in a wait state, and then to continue execution at the point when it is notified to do so. The notify method allows the thread that is running to inform the thread that is waiting that it should resume and acquire the lock.

A thread in a wait state is, in effect, waiting for some external condition to become true; the lock is the mechanism that is used to indicate this condition. When the thread is notified that the lock is available, the awaited condition has become true. The code of Figure 7 illustrates how to use the wait and notify methods. In this example, the ProcessRequest object may be called from a servlet to read and modify a single external resource within the same operation. For example, a client may retrieve a value from a column in a database table and then update that column before proceeding. Implementing the wait and notify methods in this way allows simultaneous reads, blocks reads if the resource is being modified, and allows sequential writes (i.e., only one thread can write to the resource at a time, thus avoiding a race).

The Race to Robust Code

Servlets provide a great architecture for Web applications, but Java coders must take care to manage resource contention. Perhaps the best way to control contention is simply to code your servlets so its threads will have no shared resources, which is easily accomplished by using only local variables and refraining from the use of instance variables. Another simple option is to use the single thread option—but only if you know that the servlet will have relatively few clients. But because instance variables are often a necessary evil—such as JDBC connections and record-level access file opens—you will have resort to the use of synchronized blocks. You should always try to synchronize the smallest block of code possible in order to decrease the block time. The ultimate strategy for synchronization, because it removes any opportunity for deadlock, is to use wait and notify operations.

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;


public class SimpleServlet extends HttpServlet
{

public void init(ServletConfig config)

throws ServletException

{

super.init(config);

}

public void service(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException

{

ServletOutputStream out = request.getOutputStream();

out.println("HELLO WORLD!");

}

public void destroy() {}

Figure 1: A simple servlet displays “Hello World!” on the browser.

Web Server

Simple Servlet Service( )....

Client 1

Client 3

Client 2

Response

Request

Figure 2: Multiple clients are handled by one servlet.

public class SimpleServlet extends HttpServlet
{

HttpServletRequest clientRequest;

String username = new String();

String password = new String();

public void service(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException

{

try {

clientRequest = request;

displayWelcomMessage(clientRequest);

} catch (Exception e) {}

}

public void displayWelcomMessage(

HttpServletRequest clientRequest)

throws Exception

{

username = clientRequest.getParameter("username");

password = clientRequest.getParameter("password");

ServletOutputStream out = request.getOutputStream();

out.println("Welcome " username + "! + ");

}

}

Figure 3: A simple servlet displays the input user name back to the client browser.


public class SimpleServlet extends HttpServlet implements
SingleThreadModel
{ public void service(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException

{

try {

displayWelcomMessage(request);

} catch (Exception e) {

e.printStackTrace();

}

}

public void displayWelcomMessage(

HttpServletRequest req)

throws Exception
{

String username = req.getParameter("user-name");

String password = req.getParameter("pass-word");

ServletOutputStream out = req.getOutputStream();

out.println("Welcome " username + "! + ");
}

public class SimpleServlet extends HttpServlet
{

HttpServletRequest clientRequest;

String username = new String();

String password = new String();

public void service(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException

{

try {

clientRequest = request;

displayWelcomeMessage(clientRequest);

} catch (Exception e) {}

}

public void updateDb() throws Exception{

// code omitted

synchronized(this) {

// update the database record

}

// code omitted
}

public void readDb(int prKey) throws Exception{

// code omitted

synchronized(this) {

// get the database record

}

// code omitted
}

public class ProcessRequest {

private boolean done_updating = FALSE;

public void synchronized update (object value) {

//update the resource

done_updating = TRUE;

notify();

}

public Object synchronized read() {

if (done_updating == FALSE)

wait();


Figure 4: Avoid instance variables at all costs.

Figure 5: The SingleThreadModel interface ensures that servlets run only one service method at a time.

Figure 6: Synchronizing a small block of code is more efficient than synchronizing a complete method.

//read from resource and return value

}

}

Figure 7: Ultimately, the use of wait and notify is the only way to ensure a deadlock does not occur.


BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$0.00 Raised:
$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: