Js|servlet| Multithreading | problem
Compared with ASP and PHP, servlet/jsp technology has high execution efficiency because of its multithreading operation. Because servlet/jsp is performed in multithreaded mode by default, multithreading synchronization issues need to be considered very carefully when writing code. However, many people write servlet/jsp programs and do not notice the problem of multithreading synchronization, this often causes the program to write in a small number of user access without any problems, and in the concurrent user rise to a certain value, will often appear some problems, for such a random problem debugging is very difficult.
I. Several variable types in servlet/jsp
When writing a servlet/jsp program, be careful with the instance variables. Because the instance variable is not thread safe. In servlet/jsp, variables can be grouped into the following categories:
1. Class variables
Request,response,session,config,application, as well as JSP pages built into page, PageContext. In addition to application, the other is thread-safe.
2. Instance Variables
Instance variables are instances of all, allocated in the heap. In the servlet/jsp container, you typically instantiate only one servlet/jsp instance and start multiple threads of that instance to handle the request. The instance variable is shared by all threads of the instance, so the instance variable is not thread safe.
3. Local Variables
Local variables are allocated on the stack because each thread has its own execution stack, so local variables are thread safe.
Second, the multithreading synchronization problem in the servlet/jsp
In the JSP, use instance variables with particular caution. First, look at the following code:
FFFFFF cellpadding=2 width=540 align=center bordercolorlight=black border=1>
instanceconcurrenttest.jsp<%@ page contenttype= "TEXT/HTML;CHARSET=GBK"%><%! Define instance variable String username; String password; Java.io.PrintWriter output;%><% //Get parameters from request username = Request.getparameter ("username"); Password = request.getparameter ("password"); Output = Response.getwriter (); Showuserinfo (); %> <%! public void Showuserinfo () { //to highlight the concurrency problem, a time-consuming operation of int i =0 is first performed here; Double sum = 0.0; while (i++ < 200000000) { sum = i; } Output.println (Thread.CurrentThread (). GetName () + "<br>"); Output.println ("Username:" + username + "<br>"); Output.println ("Password:" + password + "<br>"); } %>
In this page, you first define two instance variables, username and password. The two parameters are then fetched from the request and the Showuserinfo () method is invoked to echo the requested user's information back to the client's browser. In a user access Yes, there is no problem. However, when multiple users have concurrent access, there is a problem with other users ' information appearing on other users ' browsers. This is a serious problem. To highlight concurrency issues, to facilitate testing and observation, we performed a simulated time-consuming operation when echoing user information, for example, the following two users (can start two IE browsers, or on two machines simultaneously access):
A:http://localhost:8080/instanceconcurrenttest.jsp?username=a&password=123
b:http://localhost:8080/instanceconcurrenttest.jsp?username=b&password=456
If a clicks on the link, b then clicks on the link, then a will return a blank screen, and B gets the output of A and b two threads. Take a look at the screenshot below:
Figure 1:a's screen
Figure 2:b's screen
As you can see from the screenshot of the run results, the Web server started two threads to process requests from A and B, but a blank screen was found in a. This is because output in the above program, username and password are instance variables that are shared by all threads. After a accesses the page, the output is set to a, username,password the information of a, and before a executes printuserinfo () outputs username and password information, b accesses the page, The username and password are placed for the information of B, and the output is pointed to B. Then A's thread prints to the B screen, and A's username and password are replaced by B. Please take part in the following figure:
Figure 3:a, b two-thread timeline
But in the actual program, because set instance variable, use instance variable these two time points very close, so, like this example synchronization problem is not so prominent, may occasionally appear, but this is more dangerous, and more difficult to debug.
Similarly, for servlet problems with instance variables, see the servlet version of the above page:
Instanceconcurrenttest.javaimport Javax.servlet.*;import Javax.servlet.http.*;import Java.io.PrintWriter;public Class Instanceconcurrenttest extends HttpServlet {String username; String password; PrintWriter out; public void doget (HttpServletRequest request, httpservletresponse response) throws Servletexception , java.io.IOException {//Get parameters from request Username = Request.getparameter ("username"); Password = request.getparameter ("password"); System.out.println (Thread.CurrentThread (). GetName () + "| Set Username: "+ username); out = Response.getwriter (); Showuserinfo (); public void Showuserinfo () {//To highlight the concurrency problem, first execute a time-consuming operation int i = 0; Double sum = 0.0; while (i++ < 200000000) {sum = i; } out.println ("Thread:" + thread.currentthread (). GetName ()); Out.println ("Username:" + username); Out.println ("Password:" + password); }}
Third, the solution
1. Run servlet/jsp with single thread
In the JSP, by setting: <%@ page isthreadsafe= "false"%>, in the servlet, By implementing Javax.servlet.SingleThreadModel, the Web container will ensure that the JSP or servlet instance is running in a single-threaded manner.
Important: The test found that Tomcat 4.1.17 did not correctly support the IsThreadSafe property, so when you specify Istheadsafe as false, there are still multithreading problems in Tomcat 4.1.17, which is Tomcat A 4.1.17 bug. Tested through in Tomcat 3.3.1 and resin 2.1.5.
2. Remove the instance variable, pass through the parameter
As you can see from the above analysis, you should try to avoid using instance variables in servlet/jsp. For example, the following correction code eliminates the instance variables by defining local variables and passing parameters. In this way, the local variables are thread-safe because they are allocated in the thread's stack. There is no problem with multithreading synchronization. The code is as follows:
<%@ page contenttype= "TEXT/HTML;CHARSET=GBK"%><% //using local variable String username; String password; Java.io.PrintWriter output; Get the parameter username = request.getparameter ("username") from request; Password = request.getparameter ("password"); Output = Response.getwriter (); Showuserinfo (output, username, password);%><%! public void Showuserinfo (Java.io.PrintWriter _output, string _username, String _password) { //To highlight concurrency problems, Here first executes a time-consuming operation int i =0; Double sum = 0.0; while (i++ < 200000000) { sum = i; } _output.println (Thread.CurrentThread (). GetName () + "<br>"); _output.println ("Username:" + _username + "<br>"); _output.println ("Password:" + _password + "<br>"); } %>
Note: Some data indicate that the Synchronized keyword is used to synchronize the Printuserinfo () method or the relevant operation statements of instance variables, but this does not solve the problem of multithreading. This is because, while synchronizing the operation code of an instance variable, it does not prevent one thread from using another thread's modified "dirty" instance variable. Therefore, in addition to reducing operational efficiency, will not play the desired effect.