DRP (iv)--thread-safe servlet

Source: Internet
Author: User

Multi-Threading Seervlet model

The servlet specification defines that, by default (Servlets are not deployed in a distributed environment), the servlet container creates only one instance for each servlet that is declared. What happens if more than one customer requests simultaneous access to the Servlet,servlet container to handle these multiple requests? The answer is to use multi-threading, and the Servlet container maintains a line pool service request. The thread pool is actually a set of threads waiting to execute code called worker threads. The servlet container uses a dispatcher thread to manage worker threads. When a container receives a request to access a servlet, the dispatcher thread picks a worker thread from the thread pool, passes the request to the thread, and then executes the servlet's service method by this thread, such as:

When a container receives another request, the dispatcher thread picks another thread from the pool to service the new request.


because the servlet container uses single-instance multithreading (which is the default behavior of the servlet container), minimizing the overhead of producing a servlet instance significantly increases the response time to the request. For Tomcat, you canset the number of threads in the thread pool in the <Connector> element in the server. xml file.

thread safety for variables

<span style= "FONT-SIZE:24PX;" >package Org.sunxin.ch02.servlet;import Java.io.ioexception;import Java.io.printwriter;import Javax.servlet.servletexception;import Javax.servlet.http.httpservlet;import Javax.servlet.http.httpservletrequest;import Javax.servlet.http.httpservletresponse;public class WelcomeServlet Extends Httpservlet{private String greeting; String username= "";p ublic void init () {greeting = Getinitparameter ("greeting");} public void doget (HttpServletRequest req,httpservletresponse resp) throws servletexception,ioexception{ Req.setcharacterencoding ("gb2312"); username= req.getparameter ("username"); String welcomeinfo=greeting + "," + Username;resp.setcontenttype ("text/html"); PrintWriter out = Resp.getwriter (); Out.println ("

This code is primarily to show the welcome message to the user, but this code has a potential thread-safety problem. When user A and B access the servlet at the same time, it appears:

(1) The servlet container assigns a worker thread T1 to service User A's request, assigning another worker thread to T2 service User B's request.

(2) The operating system first dispatches the T1 operation.

(3) T1 executes the code, obtains the user's name from the Request object, saves it to the variable user, and now the user's value is a.

(4) When T1 tries to execute the following code, the time slice expires and the operating system dispatches T2 to run.

(5) T2 executes the code, obtains the user's name from the Request object, saves it to the variable user, and now the user's value is a.

(6) T2 continues to execute the following code, outputting "Welcome you, B" to User B.

(7) T2 execution, the operating system re-Dispatch T1 execution, T1 from the last execution of the code break continues to execute, because this time the value of the user variable has become B, so T1 to User a "Welcome you,b."

To solve this problem, you can take two ways: the first is to define username as a local variable,

<span style= "FONT-SIZE:24PX;" >package Org.sunxin.ch02.servlet;import Java.io.ioexception;import Java.io.printwriter;import Javax.servlet.servletexception;import Javax.servlet.http.httpservlet;import Javax.servlet.http.httpservletrequest;import Javax.servlet.http.httpservletresponse;public class WelcomeServlet Extends httpservlet{private String greeting;public void init () {greeting = Getinitparameter ("greeting");} public void doget (HttpServletRequest req,httpservletresponse resp) throws servletexception,ioexception{ Req.setcharacterencoding ("gb2312"); String username= req.getparameter ("username"); String welcomeinfo=greeting + "," + Username;resp.setcontenttype ("text/html"); PrintWriter out = Resp.getwriter (); Out.println ("

The second way is to synchronize the Doget () method

<span style= "FONT-SIZE:24PX;" >package Org.sunxin.ch02.servlet;import Java.io.ioexception;import Java.io.printwriter;import Javax.servlet.servletexception;import Javax.servlet.http.httpservlet;import Javax.servlet.http.httpservletrequest;import Javax.servlet.http.httpservletresponse;public class WelcomeServlet Extends Httpservlet{private String greeting; String username= "";p ublic void init () {greeting = Getinitparameter ("greeting");} Public synchronized void doget (HttpServletRequest req,httpservletresponse resp) throws servletexception,ioexception{ Req.setcharacterencoding ("gb2312"); username= req.getparameter ("username"); String welcomeinfo=greeting + "," + Username;resp.setcontenttype ("text/html"); PrintWriter out = Resp.getwriter (); Out.println ("

Because synchronization is used, it prevents multiple threads from calling the Doget () method at the same time, and avoids the possibility that the user instance variable will be modified by other threads during request processing. However, using synchronization with the Doget () method means that requests to access the same servlet will be queued, and one thread will not be able to execute another thread until the request is processed, which can severely affect performance, so we rarely use this approach.

Example:

The "Connection closedexception" described in the Tomcat documentation is shown in the following code

Package Org.sunxin.ch02.servlet;import Java.sql.connection;import Java.sql.resultset;import java.sql.Statement; Import Javax.naming.context;import Javax.naming.initialcontext;import Javax.servlet.servletexception;import Javax.servlet.http.httpservlet;import Javax.servlet.http.httpservletrequest;import    Javax.servlet.http.httpservletresponse;import Javax.sql.datasource;public class Testservlet extends HttpServlet {    DataSource ds = null;            public void init () {try{Context ctx = new InitialContext ();        Ds= (DataSource) ctx.lookup ("Java:comp/env/jdbc/bookstore");        }catch (Exception e) {e.printstacktrace (); }} public void service (HttpServletRequest request, httpservletresponse response) throws Servletexception,java. Io.        ioexception{Connection conn = null;        Statement stmt = null;        ResultSet rs = null;            try{conn=ds.getconnection ();//Get connected from the connection pool stmt = Conn.createstatement (); Rs = Stmt.executequery ("...."); //.....            Omit Rs.close ();            Stmt.close ();        Conn.close ();        }catch (Exception e) {System.out.println (e);                }finally{if (rs! = null) {try{rs.close ();                }catch (Exception e) {System.out.println (e);                }} if (stmt! = null) {try{stmt.close ();                }catch (Exception e) {System.out.println (e);                }} if (conn! = null) {try{conn.close ();                }catch (Exception e) {System.out.println (e); }            }                    }    }}

This code causes the exception to occur as follows:

(1) A database connection is obtained from the connection pool when the service of a requested thread T1 run

(2) in thread T1, when the database access operation is complete, close the database

(3) At this point, the operating system dispatches another thread T2 run

(4) T2 for another request service to access the servlet, get a database connection from the connection pool, and this connection Zheng Haowen is the connection that was put back into the pool after the close () method was just called in the T1 thread

(5) At this point, the operating system scheduler thread T1 run

(6) T1 continue to execute the following code, and in the finally statement, close the database connection again. Note that the close () method after calling the connection object only closes the database connection, and the object itself is not empty, so the closing operation in the finally statement is executed again

(7) At this point, the operating system scheduler thread T2 run.

(8) Thread T2 view uses a database connection, but fails because T1 closes the connection

(There is an article recommended: JAva.sql.Connection of what the Close method actually did )

To avoid this, we need to write the code correctly and set the object to null after closing the database object. The correct code is as follows:

<span style= "FONT-SIZE:24PX;" >package org.sunxin.ch02.servlet;import java.sql.connection;import Java.sql.resultset;import java.sql.Statement ; Import Javax.naming.context;import Javax.naming.initialcontext;import Javax.servlet.servletexception;import Javax.servlet.http.httpservlet;import Javax.servlet.http.httpservletrequest;import    Javax.servlet.http.httpservletresponse;import Javax.sql.datasource;public class Testservlet extends HttpServlet {    DataSource ds = null;            public void init () {try{Context ctx = new InitialContext ();        Ds= (DataSource) ctx.lookup ("Java:comp/env/jdbc/bookstore");        }catch (Exception e) {e.printstacktrace (); }} public void service (HttpServletRequest request, httpservletresponse response) throws Servletexception,java. Io.        ioexception{Connection conn = null;        Statement stmt = null;        ResultSet rs = null; try{conn=ds.getconnection ();//Get connected from the connection pool stmt =Conn.createstatement ();            rs = Stmt.executequery ("...."); //.....            Omit Rs.close ();            Rs=null;            Stmt.close ();            Stmt=null;   Conn.close ();//connection is put back to the connection pool conn=null;        Make sure we don't close the connection two times}catch (Exception e) {System.out.println (e);                }finally{if (rs! = null) {try{rs.close ();                }catch (Exception e) {System.out.println (e);                }} if (stmt! = null) {try{stmt.close ();                }catch (Exception e) {System.out.println (e);                }} if (conn! = null) {try{conn.close ();                }catch (Exception e) {System.out.println (e); }}}}}</span>

Thread-Safe Properties

In the servlet, you can access the properties that are stored in the Seervletcontext,httpsession and ServletRequest objects, which all three objects provide getattribute () and setattribute () method is used to read and set properties.

ServletContext

ServletContext objects can be accessed by all servlets in the Web application, and multiple threads can set or read properties in the servlet context at the same time, which results in inconsistent storage data. For example: There are two Servlet,loginservlet and Displayusersservlet. Loginservlet is responsible for validating the user and adding the user name to the list that is saved in the servlet context, and Loginservlet removes the user name from the list when the user exits. The code is as follows:

Loginservlet:

<span style= "FONT-SIZE:24PX;" >public void Service (HttpServletRequest request, httpservletresponse response) throws Servletexception, java.io.ioexception{        String username =  //Verify user        if (authenticated) {            list list= (list) Getservletcontext (). getattribute ("Userslist");        } else if (logout) {            //Removes the user name from the user list, list list            = (list) Getservletcontext (). getattribute ("Userslist");            List.remove (username);        }    } </span>
Displayusersservlet:

<span style= "FONT-SIZE:24PX;" >public void Service (HttpServletRequest request, httpservletresponse response) throws Servletexception, java.io.ioexception{        PrintWriter out = Res.getwriter;        List List = (list) Getservletcontext (). getattribute ("Userslist");        int count = List.size ();        Out.println ("

The Userslist property can be accessed by all servlets at any time, so Loginservlet may remove a user name from the list of users when Displayusersservlet loops out the user name. This causes the indexoutofboundsexcetption exception to be thrown. Access to the ServletContext property is not thread-safe, in order to avoid problems, you can synchronize access to the user list or create a copy of the user list.

HttpSession

Users can open multiple browser windows that belong to a single process, where access requests belong to the same session, in order to handle multiple requests at the same time, the servlet container creates multiple threads, and in those threads, the properties of the Sesion object can be accessed concurrently.

As an example of a shopping cart, if a user deletes an entry in one browser and then looks at all the items in the cart in another browser window, this will cause the indexoutofboundsexcetption to be thrown, to avoid this problem, and to synchronize access to the session.

ServletRequest

Because the servlet container creates a new ServletRequest object for every request it receives, the ServletRequest object is accessed only in one thread. Because there is only one thread service request, property access to the Request object is thread-safe.

Summarize

It was an eye-opener, a lot from the middle school and shared with everyone.

DRP (iv)--thread-safe servlet

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.