posts - 188,comments - 176,trackbacks - 0

           

          public class MyClass {
              
          private String variable1 ;
              
          private static String variable2 ;
              
          public MyClass(){   
              }

              
          public void method(){
                  String variable3;
              }

           }



          上面是隨手寫的一個(gè)類,沒有任何意義,只是為了強(qiáng)調(diào)一些概念,這和這個(gè)主題很有關(guān)系:
          1) java中的變量的分類:
              a. 實(shí)例變量
              b. 局部變量
              c. 靜態(tài)變量
          本篇并不是java的基礎(chǔ)教程,因此不會(huì)詳盡到每個(gè)基礎(chǔ)知識(shí)點(diǎn)(下面的內(nèi)容是區(qū)分對(duì)象和對(duì)象變量這兩個(gè)概念的,<<core java2>>嚴(yán)格區(qū)分,不過大多數(shù)教材并不過于苛刻的區(qū)別它們)
          a. 實(shí)例變量:屬于每個(gè)對(duì)象,也就是每個(gè)對(duì)象都有一份此變量的副本。上面的variable1就指向?qū)嵗兞俊?br /> b. 局部變量:工作在某個(gè)作用域,離開作用域之后成為垃圾。上面的variable3就指向局部變量,局部變量存在于方法中。
          c. 靜態(tài)變量:屬于某個(gè)類,也就是所有對(duì)象共有一個(gè)副本。上面的variable2就指向靜態(tài)變量。

          2) servlet容器的實(shí)例化:
          servlet如何被實(shí)例化的,不是我們所關(guān)心的,我們關(guān)心的是servlet被實(shí)例化了多少次,是每一次請(qǐng)求都實(shí)例化還是僅僅實(shí)例化一次?要解答這個(gè)問題太簡(jiǎn)單了:

          public class Test extends HttpServlet {
              
          private static int count = 0;
              
          private int num = 0;
             
              
          public Test() {
                  
          super();
                  count 
          ++;
                  System.out.println(
          "實(shí)例化了 "+count+" 次");
              }


              
          public void doGet(HttpServletRequest request, HttpServletResponse response)
                      
          throws ServletException, IOException {
                  response.setContentType(
          "text/html");
                  num 
          ++;
                  System.out.println(
          "被訪問了" + num+"");
              }

          }



          打開瀏覽器,訪問指定的servlet,不斷點(diǎn)刷新,結(jié)果是:
          實(shí)例化了 1 次
          被訪問了1次
          被訪問了2次
          被訪問了3次

          不要關(guān)閉瀏覽器,再開一個(gè)瀏覽器訪問,不斷點(diǎn)刷新,結(jié)果是:
          被訪問了4次
          被訪問了5次
          被訪問了6次
          被訪問了7次
          被訪問了8次

          可見對(duì)不僅僅是對(duì)同一個(gè)用戶,對(duì)于其他用戶也只實(shí)例化一個(gè)對(duì)象。
          也就是說,Tomcat僅僅實(shí)例化一次servlet,產(chǎn)生一個(gè)對(duì)象。

          那servlet容器是如何相應(yīng)多用戶同時(shí)訪問的呢?回答:多線程。為每次訪問都用一個(gè)獨(dú)立的線程運(yùn)行doGet或者是doPost方法。也就是servlet容器的內(nèi)部實(shí)現(xiàn)可能是這樣的:

          class extends Thread{
              
          public void run(){
                 
          if(request 為 get)
                     servlet.doGet();   
          // servlet指向你請(qǐng)求的servlet類的實(shí)例
                 else if(request 為 post)
                     servlet.doPost();
              }

          }



          這沒什么問題,但是一些初級(jí)程序員可能放這樣的錯(cuò)誤:

          public class Test extends HttpServlet {
              
          private PrintWriter out ;

              
          public Test() {
                  
          super();
              }


              
          public void doGet(HttpServletRequest request, HttpServletResponse response)
                      
          throws ServletException, IOException {
                  response.setContentType(
          "text/html");
                 out 
          = response.getWriter();
                 out.println(request.getRemoteAddr());
              }

          }



          會(huì)有什么結(jié)果?單A訪問這個(gè)Test,通過response.getWriter()得到一個(gè)實(shí)例,保存在out中,假定這時(shí)候B在A之前執(zhí)行完了response.getWriter(),并開始執(zhí)行out.println(request.getRemoteAddr()),這時(shí)候out保存的并不是B自己通過getWriter()方法得到的PrintWriter對(duì)象,而是A運(yùn)行g(shù)etWriter的結(jié)果,那么B就輸出了A的地址。再看看下面的例子:

          建立一個(gè)webapp,名字叫做web,建立sendname.html的HTML文件,內(nèi)容如下:

          <html>
            
          <head></head>
            
          <body>
                  
          <form action="/web/Test">
                      
          <input type="text" name="name"/>
                      
          <input type="submit" />
                  
          </form>
            
          </body>
          </html>



          建立一個(gè)servlet叫Test,內(nèi)容如下:

          public class Test extends HttpServlet {
              
          private String name ;
              
          public void doGet(HttpServletRequest request, HttpServletResponse response)
                      
          throws ServletException, IOException {
                  response.setContentType(
          "text/html");
                  PrintWriter out 
          = response.getWriter();
                  name 
          = request.getParameter("name");
                  out.println(
          "I input "+name);
                  
          try{Thread.sleep(5000);}catch(Exception ex){}
                  out.println(
          "I am "+name);
                  out.flush();
                  out.close();
              }

          }



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

          I input B I am B

          I input A I am B

          這就是Servlet中的多線程問題。解決的辦法很簡(jiǎn)單,就是不用實(shí)例變量,至少不在絕對(duì)必要的時(shí)候用。
          在JSP中這樣的問題更加突出,因?yàn)槭褂?lt;%!  %>進(jìn)行的變量聲明得到的是一個(gè)實(shí)例變量,如果一定要定義,那么就使用synchronized,在使用實(shí)例變量的方法前加上synchronized,它也是不推薦使用的,下面是一個(gè)例子:

          <%@ page contentType="text/html;charset=GB2312" %>
          <HTML>
          <BODY>

              
          <!--number 為臨界區(qū)-->
              
          <%! int number=0;    
               
          synchronized void countPeople()
                  
          { number++;
                  }

              
          %>
              
          <% countPeople();
              
          %>
          <P><P>您是第
             
          <%=number%>
          個(gè)訪問本站的客戶。
          </BODY>
          </HTML>


           


          在<%! %>中定義的方式也會(huì)被多線程調(diào)用。
          對(duì)于JSP頁(yè)面,除了使用synchronized,還可以使用page指令元素的isThreadSafe來控制整個(gè)頁(yè)面是否可以多線程訪問。


          轉(zhuǎn)CSDN
          posted on 2007-05-24 11:23 cheng 閱讀(933) 評(píng)論(0)  編輯  收藏 所屬分類: JSP/Servlet
          主站蜘蛛池模板: 奉化市| 永城市| 凯里市| 汤原县| 沁源县| 六枝特区| 永泰县| 盐池县| 广平县| 资源县| 咸阳市| 长春市| 宁波市| 宜丰县| 始兴县| 清水县| 左云县| 扬中市| 噶尔县| 房产| 卢龙县| 龙胜| 凌云县| 民县| 阳城县| 峨眉山市| 中牟县| 大埔区| 昭平县| 乌拉特前旗| 河东区| 孟州市| 叶城县| 宁安市| 太保市| 平泉县| 朝阳县| 黄浦区| 仁布县| 霍州市| 故城县|