Reference Link (slightly changed): http://www.yesky.com/334/1951334.shtml
Abstract: This article introduces the Servlet multithreading mechanism. It uses an instance and the Java memory model to explain the cause of Servlet thread insecurity and provides three solutions to ensure Servlet thread security, it also describes the trade-off between the three solutions in actual development.
Compared with ASP and PHP, Servlet/JSP has a high execution efficiency due to its multi-threaded operation. Because Servlet/JSP is executed in multi-thread mode by default
When writing code, you need to carefully consider the security of multithreading. However, many developers have not noticed the multi-thread security issue when writing Servlet/JSP programs, which often causes the compilation
The program has no problems when a small number of users access it, but when concurrent users reach a certain value, some problems will often occur.
Multi-thread mechanism of Servlet
The Servlet architecture is built on the Java multithreading mechanism, and its lifecycle is the responsibility of Web containers. When the client requests a Servlet for the first time, the Servlet container will instantiate the Servlet class according to the web. xml configuration file. When a new client requests the Servlet, the Servlet class is generally not instantiated, that is, multiple threads are using this instance. Servlet containers automatically Use thread pools and other technologies to support system running, as shown in figure 1.
In this way, when two or more threads access the same Servlet at the same time, multiple threads may access the same resource at the same time, and the data may become inconsistent. Therefore, if you do not pay attention to thread security issues when using Servlet to build Web applications, the Servlet program will be hard to find errors.
Servlet thread security issues
Servlet thread security problems are mainly caused by improper use of instance variables. Here is a realistic example.
1 public class ConcurrentTest extends HttpServlet {2 PrintWriter output; 3 @ Override 4 protected void service (HttpServletRequest request, HttpServletResponse response) 5 throws ServletException, IOException {6 String username; 7 response. setContentType ("text/html; charset = gb2312"); 8 username = request. getParameter ("username"); 9 output = response. getWriter (); 10 try {11 // to highlight the concurrency problem, set a delay of 12 threads here. sleep (5000); 13 output. println ("username:" + username + "<BR>"); 14} catch (Exception e) {15 e. printStackTrace (); 16} 17} 18}
The Servlet defines an instance variable output, which is assigned to the user output in the service method. When a user accesses the Servlet, the program runs normally, but when multiple users access the Servlet concurrently, the information of other users may be displayed on the browsers of other users. This is a serious problem. To highlight concurrency issues and facilitate testing and observation, we performed a delayed operation when returning user information. Assume that. the Servlet is registered in the xml configuration file. Currently, two users a and B can access the Servlet at the same time (two ie browsers can be started or accessed simultaneously on both machines ), enter:
A: http: // localhost: 8080/ServletTest/ConcurrentTest? Username =
B: http: // localhost: 8080/ServletTest/ConcurrentTest? Username = B
If user B is a little slower than user a's carriage return time, output 2 is displayed:
Figure 2 browser output of user a and user B
As shown in figure 2, the Web server starts two threads to process requests from user a and user B respectively, but a blank screen is displayed on user a's browser, user a's information is displayed on user B's browser. The Servlet has thread insecurity issues. Next we will start with analyzing the memory model of the instance and observe the output value of the instance variable at different times to analyze the cause of the Servlet thread being unsafe.
The Java Memory Model JMM (Java Memory Model) JMM defines the relationship between threads and Memory.According to the JMM design, the system has a Main Memory (Main Memory). All instance variables in Java are stored in the Main Memory, and all threads are shared. Each thread has its own Working Memory. The Working Memory is composed of two parts: the cache and the stack. The cache stores copies of variables in the main Memory, the cache may not always synchronize the primary memory, that is, the modifications to the variables in the cache may not be immediately written to the primary memory; the stack stores the local variables of the thread, threads cannot directly access the variables in the stack.Based on JMM, We can abstract the memory model of the Servlet instance discussed in this paper into the model shown in figure 3.
The following uses the memory model shown in Figure 3 to analyze the concurrent execution of user a and user B threads (for short, thread a and thread B, variable changes and thread execution in the Servlet instance, as shown in figure 4.
From figure 4, we can clearly see that the modification of thread B to the instance variable output overwrites the modification of thread a to the instance variable output, as a result, user a's information is displayed on user B's browser. If, when thread a executes the output statement, the changes made by thread B to the output are not refreshed to the primary storage, the output result shown in Figure 2 is not displayed. Therefore, this is just an accidental phenomenon, but this increases the potential risks of the program.
Design a thread-safe Servlet
Through the above analysis, we knowIncorrect use of instance variables is the main cause of Servlet thread insecurity.The following three solutions are provided for this problem and some reference suggestions are provided for the selection of solutions.
1. Implement the SingleThreadModel Interface
This interface specifies how the system handles calls to the same Servlet. If a Servlet is specified by this interface, no two threads will be executed simultaneously in the service method of this Servlet. Of course, there is no thread security problem. In this method, you only need to change the Class header definition of the previous Concurrent Test class:
1 public class ConcurrentTest extends HttpServlet implements SingleThreadModel {2 ... ... 3 }
Javax. servlet. SingleThreadModel API and Its Translation
Ensures that servlets handle only one request at a time. This interface has no methods.
Make sure that the servlet processes only one request at a time. The interface does not contain methods.
If a servlet implements this interface, you areGuaranteedThat no two threads will execute concurrently in the servlet'sservice
Method. The servlet container can make this guarantee by synchronizing access to a single instance of the servlet, or by maintaining a pool of servlet instances and dispatching each new request to a free servlet.
If the servlet implements this interface, it will ensure that no two threads will execute the servlet service method at the same time. The servlet container synchronizes access to the single instance of the servlet to ensure that, by maintaining the servlet instance pool, new requests are allocated to an idle servlet.
Note that SingleThreadModel does not solve all thread safety issues. for example, session attributes and static variables can still be accessed by multiple requests on multiple threads at the same time, even when SingleThreadModel servlets are used. it is recommended that a developer take other means to resolve those issues instead of implementing this interface, such as avoiding the usage of an instance variable or synchronizing the block of the code accessing those resources. this interface is deprecated in Servlet API version 2.4.
Note: SingleThreadModel does not solve all thread security risks.For example, session attributes and static variables can still be accessed simultaneously by multiple multi-threaded requests, even if SingleThreadModel servlet is used.It is recommended that developers use other methods to solve these problems, instead of implementing this interface, such as avoiding the use of instance variables or synchronizing code blocks when accessing resources. This API is not recommended in Servlet API 2.4.
2. Synchronize operations on shared data
The synchronized keyword ensures that only one thread can access the protected segment at a time. In this paper, the Servlet can guarantee thread security through synchronous block operations. The code after synchronization is as follows:
1 public class ConcurrentTest extends HttpServlet {2 PrintWriter output; 3 @ Override 4 protected void service (HttpServletRequest request, HttpServletResponse response) 5 throws ServletException, IOException {6 String username; 7 response. setContentType ("text/html; charset = gb2312"); 8 username = request. getParameter ("username"); 9 synchronized (this) {10 output = response. getWriter (); 11 try {12 // to highlight concurrency issues, set a latency of 13 threads here. sleep (1, 5000); 14 output. println ("username:" + username + "<BR>"); 15} catch (Exception e) {16 e. printStackTrace (); 17} 18} 19} 20}
3. Avoid using instance variables
Thread security issues in this instance are caused by instance variables. As long as instance variables are not used in any method in the Servlet, the Servlet is thread-safe.
Modify the Servlet code above and change the instance variable to a local variable to implement the same function. The Code is as follows:
1 public class ConcurrentTest extends HttpServlet {2 @ Override 3 protected void service (HttpServletRequest request, HttpServletResponse response) 4 throws ServletException, IOException {5 PrintWriter output; 6 String username; 7 response. setContentType ("text/html; charset = gb2312"); 8 username = request. getParameter ("username"); 9 synchronized (this) {10 output = response. getWriter (); 11 try {12 // to highlight concurrency issues, set a latency of 13 threads here. sleep (1, 5000); 14 output. println ("username:" + username + "<BR>"); 15} catch (Exception e) {16 e. printStackTrace (); 17} 18} 19} 20}
The above three methods can be tested to show that all of them can be used to design thread-safe Servlet programs. However, if a Servlet implements the SingleThreadModel interface, the Servlet engine will create a separate Servlet instance for each new request, which will cause a large amount of system overhead. SingleThreadModel is no longer recommended in Servlet2.4. If synchronization is used in a program to protect the shared data to be used, the system performance will be greatly reduced. This is because the synchronized code block can only be executed by one thread at a time, reducing the throughput for simultaneously processing customer requests and blocking many customers. In addition, to ensure data consistency between the main memory and the working memory of the thread, the cache should be refreshed frequently, which will greatly affect the system performance. Therefore, in actual development, we should also avoid or minimize the synchronization code in the Servlet; In Serlet, avoiding using instance variables is the best choice to ensure Servlet thread security. We can also know from the Java memory model that the temporary variables in the method allocate space on the stack, and each thread has its own private stack space, so they do not affect thread security.
Summary
Servlet thread security issues are only apparent when a large number of concurrent accesses are made, and are difficult to find. Therefore, pay special attention to this issue when writing Servlet programs. Thread security problems are mainly caused by instance variables. Therefore, you should avoid using instance variables in Servlet.If the application is designed to avoid using instance variables, use synchronization to protect the instance variables to be used. To ensure the optimal performance of the system, the code path with the minimum availability should be synchronized.