Servlet基礎(三) Servlet的多線程同步問題

 

Servlet基礎(三) Servlet的多線程同步問題

 

  Servlet/JSP技術和ASP、PHP等相比,因爲其多線程運行而具備很高的執行效率。java

  因爲Servlet/JSP默認是以多線程模式執行的,因此,在編寫代碼時須要很是細緻地考慮多線程的同步問題。後端

 

  若是在編寫Servlet/JSP程序時不注意到多線程的同步問題,這每每形成程序在少許用戶訪問時沒有任何問題,而在併發用戶上升到必定值時,就會常常出現一些莫名其妙的問題,對於這類隨機性的問題調試難度也很大。瀏覽器

 

  好比下面這個程序就有問題。多線程

 

存在多線程問題的程序例子

 

  這個例子中,首先有一個JSP頁面,其中有一個簡單的表單:併發

   <form action="MultiThreadServlet">
        <input type="text" name="username">
        <input type="submit" value="submit">
    </form>


  提交表單後,轉向一個Servlet進行處理:jsp

  獲取請求中的參數,而且調用setAttribute方法將其值存儲,轉向下一個jsp頁面:spa

 

package com.shengqishiwind.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 MultiThreadServlet extends HttpServlet
{
    //使用成員變量
    private String username;


    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        //從請求中獲得參數,即用戶名
        username = request.getParameter("username");
        
        //獲得當前線程的名字
        System.out.println("Thread Name: " + Thread.currentThread().getName());
        
        
        //模擬一些後端的業務處理
        try
        {
            
            Thread.sleep(10000);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        
        request.setAttribute("username", username);
        //請求轉發
        request.getRequestDispatcher("hello.jsp").forward(request, response);

    }


}

 

  中間讓線程停留了10秒鐘,來模擬一些操做。線程

 

  在下一個JSP頁面中將該值顯示出來: 調試

 

  <body>
    username: <%= request.getAttribute("username")%>
  </body>

 

 

  這樣作有什麼問題呢?code

  

  打開瀏覽器,輸入訪問地址後,輸入一個用戶名zhangsan,再打開一個窗口,輸入用戶名lisi。

  兩個瀏覽器窗口都提交之後,過了必定時間,能夠看到兩邊返回值都是lisi。

 

 

問題緣由

  Servlet的多線程同步問題:

  Servlet自己是單實例的,這樣當有多個用戶同時訪問某個Servlet時,會訪問該惟一的Servlet實例中的成員變量,若是對成員變量進行寫入操做,那就會致使Servlet的多線程問題,即數據不一致。

 

解決同步問題的方案

  1.解決Servlet多線程同步問題的最好方式:

  去除實例變量,使用局部變量。

  好比上面那個例子修改以下:

 

public class MultiThreadServlet extends HttpServlet
{
    //使用成員變量
    //private String username;


    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        //從請求中獲得參數,即用戶名
        String username = request.getParameter("username");
        
        //獲得當前線程的名字
        System.out.println("Thread Name: " + Thread.currentThread().getName());
        
        
        //模擬一些後端的業務處理
        try
        {
            
            Thread.sleep(10000);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        
        request.setAttribute("username", username);
        //請求轉發
        request.getRequestDispatcher("hello.jsp").forward(request, response);

    }


}

 

 

  不使用成員變量,而使用局部變量,由於局部變量在每一個線程中都有各自的實例。

  因此對Servlet來講,若是要對某個變量作寫入操做,必定不要使用成員變量,而要使用局部變量。

 

  2.使用同步代碼塊

  synchronized{}

  3.Servlet實現javax.serlvet.SingleThreadModel(Servlet2.4中已經廢棄了該接口),此時Servlet容器將保證Servlet實例以單線程方式運行,也就是說,同一時刻,只會有一個線程執行Servlet的service()方法。

  (這種方式瞭解一下就好了)。

 

 

參考資料

  聖思園張龍老師Java Web視頻教程。

相關文章
相關標籤/搜索