Servlet Service Method Synchronize

5
question: When we implement singlethreadmodel it means that only one thread can access the service method at a time.now my question is, why can't we achieve the same thing by making the service() method synchronized. theory says that we shouldn't synchronize the service method. But what will happen if we do so,except from the performance problem? Assume that you write a servlet and synchronize the service (...) (or any of the doXXX(...) methods or any method you call from any of these methods). Once you deploy the servlet, the servlet container receives ten "near-simultaneous" requests for the servlet. Upon receipt of the first request, the servlet container kicks off a thread and sends it on its way (i.e. starts it executing the service(...) method). Unbeknownst to the servlet container, the thread executing in the service(...) method "locks the door" behind it (holds the lock for the servlet object). Not knowing any better, the servlet container starts the other nine threads and assumes they are happily executing the service(...) method. In reality, each of the nine other threads finds the object (the servlet instance) locked, so they go into a "wait" state. Meanwhile, the first thread finishes executing the service(...) method, so it releases the lock on the servlet instance. One of the other threads--not necessarily the second thread, so we'll say the eighth thread--awakens to find the servlet's lock available, so it requests the lock and starts processing the service(...) method. Meanwhile, the servlet container may be receiving other requests. It's possible that when the eighth thread (which was the second to execute the service(...) method) finishes, the thirty- fifth thread grabs the lock. With this approach each thread has an "equal" probability of being the next allowed to execute the service(...) method.

Transcript of Servlet Service Method Synchronize

Page 1: Servlet Service Method Synchronize

question: When we implement singlethreadmodel it means that only one thread can access the service method at a time.now my question is, why can't we achieve the same thing by making the service() method synchronized. theory says that we shouldn't synchronize the service method.But what will happen if we do so,except from the performance problem?

Assume that you write a servlet and synchronize the service (...) (or any of the doXXX(...) methods or any method you call from any of these methods). Once you deploy the servlet, the servlet container receives ten "near-simultaneous" requests for the servlet. Upon receipt of the first request, the servlet container kicks off a thread and sends it on its way (i.e. starts it executing the service(...) method). Unbeknownst to the servlet container, the thread executing in the service(...) method "locks the door" behind it (holds the lock for the servlet object). Not knowing any better, the servlet container starts the other nine threads and assumes they are happily executing the service(...) method. In reality, each of the nine other threads finds the object (the servlet instance) locked, so they go into a "wait" state. Meanwhile, the first thread finishes executing the service(...) method, so it releases the lock on the servlet instance. One of the other threads--not necessarily the second thread, so we'll say the eighth thread--awakens to find the servlet's lock available, so it requests the lock and starts processing the service(...) method. Meanwhile, the servlet container may be receiving other requests. It's possible that when the eighth thread (which was the second to execute the service(...) method) finishes, the thirty-fifth thread grabs the lock. With this approach each thread has an "equal" probability of being the next allowed to execute the service(...) method. It's complete anarchy--every thread for itself. About this time, the person who sent the second request is calling you to say that your application is down. :) And, if you really want things to get complex, try synchronizing the service (...) method and the doXXX(...) methods... So what does the servlet container do? It provides queuing and prioritization (generally first-in-first-out) of requests. Some servlet containers instantiate multiple servlet objects (and maintain a servlet pool--remember that synchronizing a method locks the object (or instance), not the method, so multiple threads can execute the same method in different instances) to handle multiple simultaneous requests. (Note that this means that you may need to synchronize access of static members.)

Page 2: Servlet Service Method Synchronize

Others (like Tomcat, IIRC) provide as little support for SingleThreadModel servlets as is required by the servlet specification (they don't waste time creating object pools) since using SingleThreadModel is a "cop out." Keep reading, I'll explain why... :) Implementing the interface often gives developers a false sense of security when it comes to multi-threaded programming. For example, regardless of whether your servlet implements SingleThreadModel or not, you still need to consider synchronization problems with static members, HttpSession attributes, ServletContext attributes, and any other classes outside the scope of the servlet (i.e. JavaBeans, support classes, etc.).So, what do you do if you're not sure whether your servlet is thread-safe? Your best bet is to talk with other developers who have more experience in multi-threaded programming (someone who's been doing it for 30 years is a good beginner ;). Also, do all you can to learn about the topic. IBM's DeveloperWorks website has a lot of articles on multi-threaded programming, including Understand that for instance methods, synchronized locks obj..., Threading lightly, Part 1: Synchronization is not the enemy (and parts 2 and 3), and many, many more. Also, check out some of their tutorials, like Introduction to Java threads.

How do I ensure that my servlet is thread-safe?

The init() method is guaranteed to be called once per servlet instance, when the servlet is loaded. You don't have to worry about thread safety inside this method, since it is only called by a single thread, and the web server will wait until that thread exits before sending any more threads into your service() method.

Every new client request generates (or allocates) a new thread; that thread calls the service () method of your servlet (which may in turn call doPost (), doGet () and so forth).

Under most circumstances, there is only one instance of your servlet, no matter how many client requests are in process. That means that at any given moment, there may be many threads running inside the service() method of your solo instance, all sharing the same instance data and potentially stepping on each other's toes. This means that you should be careful to synchronize access to shared data (instance variables) using the synchronized keyword.

Page 3: Servlet Service Method Synchronize

(Note that the server will also allocate a new instance if you register the servlet with a new name and, e.g., new init parameters.)

Note that you need not (and should not) synchronize on local data or parameters. And especially you shouldn't synchronize the service () method! (Or doPost (), doGet() et al.)

A simple solution to synchronizing is to always synchronize on the servlet instance itself using synchronized (this) { ... }. However, this can lead to performance bottlenecks; you're usually better off synchronizing on the data objects themselves.

If you absolutely can't deal with synchronizing, you can declare that your servlet implements SingleThreadModel. This empty interface tells the web server to only send one client request at a time into your servlet. From the JavaDoc: If the target servlet is flagged with this interface, the servlet programmer is guaranteed that no two threads will execute concurrently the service method of that servlet. This guarantee is ensured by maintaining a pool of servlet instances for each such servlet, and dispatching each service call to a free servlet. In essence, if the servlet implements this interface, the servlet will be thread safe Note that this is not an ideal solution, since performance may suffer (depending on the size of the instance pool), plus it's more difficult to share data across instances than within a single instance.

See also What's a better approach for enabling thread-safe servlets and JSPs? SingleThreadModel Interface or Synchronization?

To share data across successive or concurrent requests, you can use either instance variables or class-static variables, or use Session Tracking.

The destroy() method is not necessarily as clean as the init() method. The server calls destroy either after all service calls have been completed, or after a certain number of seconds have passed, whichever comes first. This means that other threads might be running service requests at the same time as your destroy() method is called! So be sure to synchronize, and/or wait for the other requests to quit. Sun's Servlet Tutorial has an example of how to do this with reference counting.

Page 4: Servlet Service Method Synchronize

destroy () can not throw an exception, so if something bad happens, call log() with a helpful message (like the exception). See the closing a JDBC connection example in Sun's Tutorial.