Servlet的線程安全

Servlet的線程安全

1、什麼是Servlet的線程安全

  1.在Servlet的整個生命週期中,構造方法只被執行一次。也就是說,在Servlet的整個生命週期中,只存在一個Servlet實例對象。這說明Servlet是單例多線程的,可能會引發線程安全問題。java

所謂線程安全就是一個Servlet實例對象會同時處理多個請求,這樣的Servlet工做效率的確很高。但若是Servlet中包含成員變量的話,可能一個線程對該成員變量進行寫操做,而另外一個線程對該成員變量進行讀操做。因此,單例多線程的Servlet不能建立成員變量。瀏覽器

  下面我將經過例子討論線程安全問題(不存在線程安全問題的代碼:)安全

 1 package gacl.servlet.study;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.ServletException;
 6 import javax.servlet.http.HttpServlet;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9   
10         /**
11          * 當多線程併發訪問這個方法裏面的代碼時,會存在線程安全問題嗎??
12          * i變量被多個線程併發訪問,可是沒有線程安全問題,由於i是doGet方法裏面的局部變量,
13          * 當有多個線程併發訪問doGet方法時,每個線程裏面都有本身的i變量,
14          * 各個線程操做的都是本身的i變量,因此不存在線程安全問題
15          * 多線程併發訪問某一個方法的時候,若是在方法內部定義了一些資源(變量,集合等)
16          * 那麼每個線程都有這些東西,因此就不存在線程安全問題了
17          */
18 public class ServletThread extends HttpServlet {
19 
20     
21     public void doGet(HttpServletRequest request, HttpServletResponse response)
22             throws ServletException, IOException {
23         int a=1;
24         a++;
25         response.getWriter().write(a);
26     }
27 
28     public void doPost(HttpServletRequest request, HttpServletResponse response)
29             throws ServletException, IOException {
30         doGet(request, response);
31     }
32 
33 }

存在線程安全問題的代碼:多線程

 1 package gacl.servlet.study;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.ServletException;
 6 import javax.servlet.http.HttpServlet;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9 
10 public class ServletTreadDemo extends HttpServlet {
11 
12     int i=1;
13     public void doGet(HttpServletRequest request, HttpServletResponse response)
14             throws ServletException, IOException {
15         i++;
16         try {
17             Thread.sleep(1000*3);
18         } catch (InterruptedException e) {
19             e.printStackTrace();
20         }
21         response.getWriter().write(i+"");
22     }
23 
24     public void doPost(HttpServletRequest request, HttpServletResponse response)
25             throws ServletException, IOException {
26         doGet(request, response);
27     }
28 
29 }

把i定義成全局變量,多個線程併發訪問變量全局變量 i 時,就會存在線程安全問題了,若是同時開啓兩個瀏覽器模擬併發訪問同一個Servlet,原本正常來講,第一個瀏覽器應該看到2,而第二個瀏覽器應該看到3的,結果兩個瀏覽器都看到了3。併發

2.線程安全問題的解決辦法:

1.加鎖(synchronized)this

  加了synchronized後,併發訪問i時就不存在線程安全問題了,爲何加了synchronized後就沒有線程安全問題了呢?假如如今有一個線程訪問Servlet對象,那麼它就先拿到了Servlet對象的那把鎖等到它執行完以後纔會把鎖還給Servlet對象,因爲是它先拿到了Servlet對象的那把鎖,因此當有別的線程來訪問這個Servlet對象時,因爲鎖已經被以前的線程拿走了,後面的線程只能排隊等候了。。這樣不科學。。若是有1000人同時訪問ServletThreadDemo1。後面的人還不等得得吐血!!spa

 1 package gacl.servlet.study;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.ServletException;
 6 import javax.servlet.http.HttpServlet;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9 
10 
11 public class ServletThreadDemo1 extends HttpServlet {
12 
13     int i=1;
14     public void doGet(HttpServletRequest request, HttpServletResponse response)
15             throws ServletException, IOException {
16         synchronized (ServletThreadDemo1.class) {//在java中,每個對象都有一把鎖,這裏的this指的就是Servlet對象
17             i++;
18             try {
19                 Thread.sleep(5000*2);
20             } catch (InterruptedException e) {
21                 e.printStackTrace();
22             }
23             response.getWriter().println(i+"");
24         }
25         
26     }
27 
28     public void doPost(HttpServletRequest request, HttpServletResponse response)
29             throws ServletException, IOException {
30         doGet(request, response);
31     }
32 }

 

2.sun公司給的解決方案是:若是某個Servlet實現了SingleThreadModel接口,那麼Servlet引擎將以單線程模式來調用其service方法。 SingleThreadModel接口中沒有定義任何方法,只要在Servlet類的定義中增長實現SingleThreadModel接口的聲明便可。 對於實現了SingleThreadModel接口的Servlet,Servlet引擎仍然支持對該Servlet的多線程併發訪問,其採用的方式是產生多個Servlet實例對象,併發的每一個線程分別調用一個獨立的Servlet實例對象。 可是實現SingleThreadModel接口並不能真正解決Servlet的線程安全問題,由於Servlet引擎會建立多個Servlet實例對象,而真正意義上解決多線程安全問題是指一個Servlet實例對象被多個線程同時調用的問題。事實上,在Servlet API 2.4中,已經將SingleThreadModel標記爲Deprecated(過期的)。線程

相關文章
相關標籤/搜索