【轉】多使用者訪問Servlet,servlet單一實例多線程

來源:互聯網
上載者:User

標籤:

  1. public class MyClass {  
  2.     private String variable1 ;  
  3.     private static String variable2 ;  
  4.     public MyClass(){     
  5.     }  
  6.     public void method(){  
  7.         String variable3;  
  8.     }  
  9.  }  

上面是隨手寫的一個類,沒有任何意義,只是為了強調一些概念,這和這個主題很有關係:
1) java中的變數的分類:
    a. 執行個體變數
    b. 局部變數
    c. 靜態變數
本篇並不是java的基礎教程,因此不會詳盡到每個基礎知識點(下面的內容是區分對象和物件變數這兩個概念的,<<core java2>>嚴格區分,不過大多數教材並不過於苛刻的區別它們)
a. 執行個體變數:屬於每個對象,也就是每個對象都有一份此變數的副本。上面的variable1就指向執行個體變數。
b. 局部變數:工作在某個範圍,離開範圍之後成為垃圾。上面的variable3就指向局部變數,局部變數存在於方法中。
c. 靜態變數:屬於某個類,也就是所有對象共有一個副本。上面的variable2就指向靜態變數。

2) servlet容器的執行個體化:
servlet如何被執行個體化的,不是我們所關心的,我們關心的是servlet被執行個體化了多少次,是每一次請求都執行個體化還是僅僅執行個體化一次?要解答這個問題太簡單了:

 

 

[java] view plaincopy 
  1. public class Test extends HttpServlet {  
  2.     private static int count = 0;  
  3.     private int num = 0;  
  4.      
  5.     public Test() {  
  6.         super();  
  7.         count ++;  
  8.         System.out.println("執行個體化了 "+count+" 次");  
  9.     }  
  10.   
  11.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
  12.             throws ServletException, IOException {  
  13.         response.setContentType("text/html");  
  14.         num ++;  
  15.         System.out.println("被訪問了" + num+"次");  
  16.     }  
  17. }  



 

開啟瀏覽器,訪問指定的servlet,不斷點重新整理,結果是:
執行個體化了 1 次
被訪問了1次
被訪問了2次
被訪問了3次

不要關閉瀏覽器,再開一個瀏覽器訪問,不斷點重新整理,結果是:
被訪問了4次
被訪問了5次
被訪問了6次
被訪問了7次
被訪問了8次

可見對不僅僅是對同一個使用者,對於其他使用者也只執行個體化一個對象。
也就是說,Tomcat僅僅執行個體化一次servlet,產生一個對象。

那servlet容器是如何相應多使用者同時訪問的呢?回答:多線程。為每次訪問都用一個獨立的線程運行doGet或者是doPost方法。也就是servlet容器的內部實現可能是這樣的:

 

[java] view plaincopy 
  1. class . extends Thread{  
  2.     public void run(){  
  3.        if(request 為 get)  
  4.            servlet.doGet();   // servlet指向你請求的servlet類的執行個體  
  5.        else if(request 為 post)  
  6.            servlet.doPost();  
  7.     }  
  8. }  



這沒什麼問題,但是一些初級程式員可能放這樣的錯誤:

 

 

[java] view plaincopy 
  1. public class Test extends HttpServlet {  
  2.     private PrintWriter out ;  
  3.   
  4.     public Test() {  
  5.         super();  
  6.     }  
  7.   
  8.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
  9.             throws ServletException, IOException {  
  10.         response.setContentType("text/html");  
  11.        out = response.getWriter();  
  12.        out.println(request.getRemoteAddr());  
  13.     }  
  14. }  



會有什麼結果?單A訪問這個Test,通過response.getWriter()得到一個執行個體,儲存在out中,假定這時候B在A之前執行完了response.getWriter(),並開始執行out.println(request.getRemoteAddr()),這時候out儲存的並不是B自己通過getWriter()方法得到的PrintWriter對象,而是A運行getWriter的結果,那麼B就輸出了A的地址。再看看下面的例子:

建立一個webapp,名字叫做web,建立sendname.html的HTML檔案,內容如下:

 

 

 

[java] view plaincopy 
  1. <html>  
  2.   <head></head>  
  3.   <body>  
  4.         <form action="/web/Test">  
  5.             <input type="text" name="name"/>  
  6.             <input type="submit" />  
  7.         </form>  
  8.   </body>  
  9. </html>  



建立一個servlet叫Test,內容如下:

 

 

 

[java] view plaincopy 
  1. public class Test extends HttpServlet {  
  2.     private String name ;  
  3.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
  4.             throws ServletException, IOException {  
  5.         response.setContentType("text/html");  
  6.         PrintWriter out = response.getWriter();  
  7.         name = request.getParameter("name");  
  8.         out.println("I input "+name);  
  9.         try{Thread.sleep(5000);}catch(Exception ex){}  
  10.         out.println("I am "+name);  
  11.         out.flush();  
  12.         out.close();  
  13.     }  
  14. }  



通過瀏覽器開啟2個sendname.html(http://localhost:8080/web/sendname.html),分別輸入名字A和B(間隔不要超過5秒):
結果2個頁面顯示分別是:

I input B I am B

I input A I am B

這就是Servlet中的多線程問題。解決的辦法很簡單,就是不用執行個體變數,至少不在絕對必要的時候用。
在JSP中這樣的問題更加突出,因為使用<%!  %>進行的變數聲明得到的是一個執行個體變數,如果一定要定義,那麼就使用synchronized,在使用執行個體變數的方法前加上synchronized,它也是不推薦使用的,下面是一個例子:

[java] view plaincopy 
  1. <%@ page contentType="text/html;charset=GB2312" %>  
  2. <HTML>  
  3. <BODY>  
  4.   
  5.     <!--number 為臨界區-->  
  6.     <%! int number=0;      
  7.      synchronized void countPeople()  
  8.         { number++;  
  9.         }  
  10.     %>  
  11.     <% countPeople();  
  12.     %>  
  13. <P><P>您是第  
  14.    <%=number%>  
  15. 個訪問本站的客戶。  
  16. </BODY>  
  17. </HTML>  


在<%! %>中定義的方式也會被多線程調用。
對於JSP頁面,除了使用synchronized,還可以使用page指令元素的isThreadSafe來控制整個頁面是否可以多線程訪問。

【轉】多使用者訪問Servlet,servlet單一實例多線程

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.