Section 3.9. Thread Safety


3.9. Thread Safety

In a typical scenario, only one copy of any particular servlet or filter is loaded into the server's runtime at any given time. Each servlet might, however, be called upon to deal with multiple requests at the same time. This means that a servlet needs to be threadsafe. If a servlet doesn't use any class variables (that is, any variables with a scope broader than the service method itself), it is generally already threadsafe. If you are using any third-party libraries or extensions, make sure that those components are also threadsafe. However, a servlet that maintains persistent resources needs to make sure that nothing untoward happens to those resources. Imagine, for example, a servlet that maintains a bank balance using an int in memory.[*] If two servlets try to access the balance at the same time, you might get this sequence of events:

[*] Hey, bear with us on this. It's an example.

  1. User 1 connects to the servlet to make a $100 withdrawal.

  2. The servlet checks the balance for User 1, finding $120.

  3. User 2 connects to the servlet to make a $50 withdrawal.

  4. The servlet checks the balance for User 2, finding $120.

  5. The servlet debits $100 for User 1, leaving $20.

  6. The servlet debits $50 for User 2, leaving -$30.

  7. The programmer is fired.

Obviously, this is incorrect behavior, particularly that last bit. We want the servlet to perform the necessary action for User 1, and then deal with User 2 (in this case, by giving him an insufficient funds message). We can do this by surrounding sections of code with synchronized blocks. While a particular synchronized block is executing, no other sections of code that are synchronized on the same object (usually the servlet or the resource being protected) can execute. For more information on thread safety and synchronization, see Java Threads by Scott Oaks and Henry Wong (O'Reilly).

Example 3-6 implements the ATM display for the First Bank of Java. The doGet( ) method displays the current account balance and provides a small ATM control panel for making deposits and withdrawals, as shown in Figure 3-3.[]

] Despite the fact that Java is a very large island, theres still only one account.

Figure 3-3. The First Bank of Java ATM display


The control panel uses a POST request to send the transaction back to the servlet, which performs the appropriate action and calls doGet( ) to redisplay the ATM screen with the updated balance.

Example 3-6. An ATM servlet
 import javax.servlet.*; import javax.servlet.http.*; import java.util.*; import java.io.*;   public class AtmServlet extends HttpServlet {     Account act;     public void init(ServletConfig conf) throws ServletException {     super.init(conf);     act = new Account(  );     act.balance = 0;   }     public void doGet(HttpServletRequest req, HttpServletResponse resp)     throws ServletException, IOException {       resp.setContentType("text/html");     PrintWriter out = resp.getWriter(  );       out.println("<html><body>");     out.println("<h2>First Bank of Java ATM</h2>");     out.println("Current Balance: <b>" + act.balance + "</b><br>");     out.println("<form method=post>");     out.println("Amount: <input type=text name=AMOUNT size=3><br>");     out.println("<input type=submit name=DEPOSIT value=\"Deposit\">");     out.println("<input type=submit name=WITHDRAW value=\"Withdraw\">");     out.println("</form>");     out.println("</body></html>");   }     public void doPost(HttpServletRequest req, HttpServletResponse resp)     throws ServletException, IOException {       int amt=0;     try {       amt = Integer.parseInt(req.getParameter("AMOUNT"));     }     catch (NullPointerException e) {       // No Amount parameter passed     }     catch (NumberFormatException e) {       // Amount parameter was not a number     }       synchronized(act) {       if((req.getParameter("WITHDRAW") != null) && (amt < act.balance))         act.balance = act.balance - amt;       if((req.getParameter("DEPOSIT") != null) && (amt > 0))         act.balance = act.balance + amt;     } // End synchronized block       doGet(req, resp);                   // Show ATM screen   }     public void destroy(  ) {     // This is where we would save the balance to a file   }     class Account {     public int balance;   } }

The doPost( ) method alters the account balance contained within an Account object act (since Account is so simple, we've defined it as an inner class). In order to prevent multiple requests from accessing the same account at once, any code that alters act is synchronized on act. This ensures that no other code can alter act while a synchronized section is running.

The destroy( ) method is defined in the AtmServlet, but it contains no actual code. A real banking servlet would obviously want to write the account balance to disk before being unloaded. And if the servlet were using JDBC to store the balance in a database, it would also want to destroy all its database-related objects.

Servlet API 2.4 deprecates the SingleThreadModel interface, which was a tag interface to identify a servlet that could serve only one request at a time. Since SingleThreadModel could not resolve all potential threading issues, it has been deprecated and should not be used in new development.




Java Enterprise in a Nutshell
Java Enterprise in a Nutshell (In a Nutshell (OReilly))
ISBN: 0596101422
EAN: 2147483647
Year: 2004
Pages: 269

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net