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, You need to carefully consider the multi-thread
SecurityProblem. However, many developers have not noticed the multi-thread security issue when writing Servlet/jsp programs, which often causes no problems when a few users access the program, when the number of concurrent users reaches a certain value, some unknown problems 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.
Figure 1 servlet Thread Pool |
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.
Import javax. servlet .*; Import javax. servlet. http .*; Import Java.Io.*;
Public class Concurrent Test extends httpservlet {printwriter output; Public void Service (httpservletrequest request, Httpservletresponse response) throws servletexception, ioexception {string username; Response. setcontenttype ("text/html; charset = gb2312 "); Username = request. getparameter ("username "); Output = response. getwriter (); Try {thread. Sleep (5000); // to highlight concurrency issues, set a latency here } Catch (interrupted exception e ){} Output. println ("username:" + username + "<br> "); } } |
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 . 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/servlet/concurrenttest? Username =
B: http: // localhost: 8080/servlet/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.
Java Memory Model jmm (Java
Memory
Model) Jmm is mainly used to specify the relationship between threads and memory. According to Design The system has a main memory (main memory). All instance variables in Java are stored in the main memory. Share . Each thread has its own working memory (Working
Memory), the working memory is composed of two parts: the cache and the stack. The cache stores copies of the variables in the primary memory, and the cache may not always synchronize the primary memory, that is, the changes to the variables in the cache may not be immediately written to the primary storage. The local variables of the thread are saved in the stack, and the variables in the stack cannot be directly accessed between threads. Based on jmm, we can Thesis The memory model of the servlet instance discussed in is abstracted as the model shown in figure 3.
Figure 3 jmm model of the servlet instance |
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.
Scheduling time |
Thread |
Line B |
T1 |
Access the servlet page |
|
T2 |
|
Access the servlet page |
T3 |
Output = username of output = a sleep for 5000 milliseconds, giving way to the CPU |
|
T4 |
|
Output = B's output (written back to the primary storage) username = B sleep for 5000 milliseconds, giving the CPU |
T5 |
Output the username value of thread a in user B's browser, and thread a terminates. |
|
T6 |
|
Output the username value of line B in user B's browser, and line B is terminated. |
Figure 4 servlet instance Thread Scheduling
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 know that incorrect 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:
Public class Concurrent Test extends httpservlet implements singlethreadmodel { ............ } |
2. Synchronize operations on shared data
The synchronized keyword ensures that only one thread can access Protection In this paper, servlet can guarantee thread security by synchronizing block operations. The code after synchronization is as follows:
............ Public class Concurrent Test extends httpservlet {............ Username = request. getparameter ("username "); Synchronized (this ){ Output = response. getwriter (); Try { Thread. Sleep (5000 ); } Catch (interrupted exception e ){} Output. println ("username:" + username + "<br> "); } } } |
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:
...... Public class Concurrent Test extends httpservlet {public void Service (httpservletrequest request, httpservletresponse
Response) throws servletexception, ioexception { Print Writer output; String username; Response. setcontenttype ("text/html; charset = gb2312 "); ...... } } |
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
Synchronous Code in servlet; avoiding using instance variables in serlet 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.