Compared with ASP and PHP, Servlet/jsp has a high execution efficiency due to its multi-threaded operation. Servlet/JSP is executed in multi-thread mode by default. Therefore, you must carefully consider the multi-thread synchronization issue when writing code. However, many developers did not notice the problem of multi-thread synchronization when writing Servlet/jsp programs, which often caused no problems when a few users access the program, when concurrent users reach a certain value, some unknown problems often occur, and debugging is difficult for such random problems.
I. variable types in Servlet/jsp
When writing Servlet/jsp programs, be careful when using instance variables. Because instance variables are non-thread-safe. In Servlet/JSP, variables can be classified into the following categories:
1. class variables
Request, response, session, config, application, and built-in pages and pagecontext of JSP pages. All applications are thread-safe.
2. instance variables
Instance variables are owned by instances and allocated in the heap. In Servlet/jsp containers, only one Servlet/jsp instance is instantiated, and multiple threads of the instance are started to process requests. Instance variables are shared by all threads of the instance. Therefore, instance variables are not thread-safe.
3. Local Variables
Local variables are allocated in the stack. Because each thread has its own execution stack, local variables are thread-safe.
Ii. multi-thread synchronization in Servlet/jsp
In JSP, be cautious when using instance variables. First, see the following code:
// Instanceconcurrenttest. jsp
<% @ Page contenttype = "text/html; charset = GBK" %>
<%!
// Define instance variables
String username;
String password;
Java. Io. printwriter output;
%>
<%
// Obtain parameters from the request
Username = request. getparameter ("username ");
Password = request. getparameter ("password ");
Output = response. getwriter ();
Showuserinfo ();
%>
<%!
Public void showuserinfo (){
// To highlight the concurrency problem, perform a time-consuming operation here
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> ");
}
%>
On this page, we first define two instance variables: username and password. Then obtain the two parameters from the request and call the showuserinfo () method to display the information of the requesting user in the client's browser. There is no problem during a user access. However, when multiple users access the service concurrently, the information of other users is displayed on the browsers of other users. This is a serious problem. To highlight concurrency issues and facilitate testing and observation, we performed a simulated time-consuming operation when returning the user information. For example, the following two users can simultaneously access the site (two ie browsers can be started, or access the service on both machines at the same time ):
A: http: // localhost: 8080/instanceconcurrenttest. jsp? Username = A & Password = 123
B: http: // localhost: 8080/instanceconcurrenttest. jsp? Username = B & Password = 456
If a clicks the link and B clicks the link again, a returns a blank screen, and B gets the output of both threads A and B. See the following screen:
Figure 1: A's screen
Figure 2: B's screen
The running result shows that the Web server starts two threads to process requests from A and B respectively, but a gets a blank screen in. This is because the output, username, and password in the above program are both instance variables and are shared by all threads. After a accesses this page, it sets output to a's output, username, and password to a's information respectively. Before a executes printuserinfo () to output username and password information, B visited the page again, set username and password to B, and point the output to B. When the thread of a is printed, it is printed to the screen of B, and the user name and password of A are also replaced by B. See:
Figure 3: timeline of two threads A and B
In the actual program, because the instance variables are set, the two time points of the instance variables are very close, so the synchronization problem in this example is not so prominent and may occasionally occur, however, this is more dangerous and difficult to debug.
Similarly, the servlet also has the multi-thread problem of instance variables. Please refer to the servlet version on the above page:
// Instanceconcurrenttest. Java
Import 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
{
// Obtain parameters from the 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, perform a time-consuming operation here
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 );
}
}
Iii. Solutions
1. Run Servlet/JSP in a single thread
In JSP, set: In servlet, implement javax. servlet. singlethreadmodel. In this case, the Web Container will ensure that JSP or servlet instances run in a single thread mode.
Note: during the test, we found that Tomcat 4.1.17 does not correctly support the isthreadsafe attribute. Therefore, after you set istheadsafe to false, multithreading still occurs in Tomcat 4.1.17, which is a bug in Tomcat 4.1.17. The test passed in Tomcat 3.3.1 and resin 2.1.5.
2. Remove instance variables and PASS Parameters
From the above analysis, we can avoid using instance variables in Servlet/JSP. For example, the following correction code removes instance variables, defines local variables, and transmits parameters. In this way, because local variables are allocated in the thread stack, It is thread-safe. No multi-thread synchronization issues. The Code is as follows:
<% @ Page contenttype = "text/html; charset = GBK" %>
<%
// Use local variables
String username;
String password;
Java. Io. printwriter output;
// Obtain parameters from the request
Username = request. getparameter ("username ");
Password = request. getparameter ("password ");
Output = response. getwriter ();
Showuserinfo (output, username, password );
%>
<%!
Public void showuserinfo (Java. Io. printwriter _ output,
String _ username, string _ password ){
// To highlight the concurrency problem, perform a time-consuming operation here
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 documents indicate that synchronized keywords are used for synchronization in the printuserinfo () method or related operation statements of instance variables, but this does not solve the problem of multithreading. Because, although the operation code of instance variables can be synchronized, it does not prevent a thread from using the "dirty" instance variable modified by another thread. Therefore, in addition to reducing the operating efficiency, it will not achieve the expected results.