posts - 188,comments - 176,trackbacks - 0

           

          JSP默認是以多線程方式執行的,這是JSP與ASP,PHP,PERL等腳本語言不一樣的地方,也是它的優勢之一,但如果不注意多線程中的同步問題,會使所寫的JSP程序有難以發現的錯誤。下面以一個例子說明JSP中的多線程問題及解決方法。

           

          一、JSP的中存在的多線程問題:

          當客戶端第一次請求某一個JSP文件時,服務端把該JSP編譯成一個CLASS文件,并創建一個該類的實例,然后創建一個線程處理CLIENT端的請求。如果有多個客戶端同時請求該JSP文件,則服務端會創建多個線程。每個客戶端請求對應一個線程。以多線程方式執行可大大降低對系統的資源需求,提高系統的并發量及響應時間.對JSP中可能用的的變量說明如下:

          實例變量


          實例變量是在堆中分配的,并被屬于該實例的所有線程共享,所以不是線程安全的.


          JSP系統提供的8個類變量


          JSP中用到的OUT,Request,Response,Session,Config,Page,PageConxt是線程安全的,Application在整個系統內被使用,所以不是線程安全的.


          局部變量


          局部變量在堆棧中分配,因為每個線程都有它自己的堆棧空間,所以是線程安全的.


          靜態類


          靜態類不用被實例化,就可直接使用,也不是線程安全的.


          外部資源:


          在程序中可能會有多個線程或進程同時操作同一個資源(如:多個線程或進程同時對一個文件進行寫操作).此時也要注意同步問題.

          二、下面的例子存在的多線程問題:

          <%@ page import="
          javax.naming.*,
          java.util.*,
          java.sql.*,
          weblogic.common.*
          " %>

          <%@ page import=" 
          Javax.naming.*
          java.util.
          *
          java.sql.
          *
          Weblogic.common.
          * 
          " %> 



          <% 
          String name 
          String product; 
          long quantity; 


          name
          =request.getParameter("name"); 
          product
          =request.getParameter("product"); 
          quantity
          =request.getParameter("quantity"); /*(1)*/ 
          savebuy(); 
          %> 


          <%! 
          public void savebuy() 

          /*進行數據庫操作,把數據保存到表中*/ 
          try 
          Properties props 
          = new Properties(); 
          props.put(
          "user","scott"); 
          props.put(
          "password","tiger"); 
          props.put(
          "server","DEMO"); 

          Driver myDriver 
          = (Driver) iver").newInstance(); 
          conn = myDriver.connect("JDBC:weblogic:Oracle", props); 
          stmt 
          = conn.createStatement(); 

          String inssql 
          = "insert into buy(empid, name, dept) values (?, ?, ?,?)"
          stmt 
          = conn.prepareStatement(inssql); 

          stmt.setString(
          1, name); 
          stmt.setString(
          2, procuct); 
          stmt.setInt(
          3, quantity); 
          stmt.execute(); 
          }
           
          catch (Exception e) 

          System.out.println(
          "SQLException was thrown: " + e.getMessage()); 
          }
           
          finally //close connections and { 
          try 
          if(stmt != null
          stmt.close(); 
          if(conn != null
          conn.close(); 
          }
           catch (SQLException sqle) 
          System.out.println(
          "SQLException was thrown: " + sqle.getMessage()); 
          }
           
          }
           

          %> 

          <%!
          public void  savebuy()
          {
              /*進行數據庫操作,把數據保存到表中*/
              try {
                Properties props = new Properties();
                props.put("user","scott");
                props.put("password","tiger");
                props.put("server","DEMO");  

                Driver myDriver = (Driver) iver").newInstance();
                conn = myDriver.connect("jdbc:weblogic:oracle", props);
                stmt = conn.createStatement();
             
                String inssql = "insert into buy(empid, name, dept) values (?, ?, ?,?)";
                stmt = conn.prepareStatement(inssql);

                stmt.setString(1, name);
                stmt.setString(2, procuct);   
                stmt.setInt(3, quantity);
                stmt.execute();
              }
              catch (Exception e)
              {
                  System.out.println("SQLException was thrown: " + e.getMessage());
              }
              finally //close connections and     {
                  try {
                    if(stmt != null)
                      stmt.close();
                    if(conn != null)
                      conn.close();
                  } catch (SQLException sqle) {
                      System.out.println("SQLException was thrown: " + sqle.getMessage());
                  }
              }
          }
          %>

          上面的程序模擬網上購物中的一部分,把用戶在瀏覽器中輸入的用戶名,購買的物品名稱,數量保存到表BUY中。在savebuy()函數中用到了實例變量,所以它不是線程安全的.因為:程序中的每一條語句都不是原子操作,如name=request.getParameter("name");在執行是會對應多個機器指令,在任何時候都可能因系統調度而轉入睡眠狀態,讓其他的線程繼續執行.如果線程A在執行到(1)的時候轉入睡眠狀態,線程B開始執行并改變QUANTITY的值,那么當又到A執行時,它會從調用savebuy()函數開始執行,這樣它保存到表中的QUANTITY是被線程B改過的值,那么線程A對應的用戶所實際購買的數量與保持到表中的數據不一致.這是個很嚴重的問題.

          三、解決方法

           

          1.采用單線程方式

          在該JSP文件中加上: ,使它以單線程方式執行,這時,仍然只有一個實例,所有客戶端的請求以串行方 式執行。這樣會降低系統的性能.

           2.對函數savebuy()加synchronized進行線程同步,該JSP仍然以多線程方式執行,但也會降低系統的性能

          public synchronized void savebuy() 

                  
          }
           

           3.采用局部變量代替實例變量

          函數savebuy()聲明如下:因為在savebuy()中使用的是傳給他的形參,是在堆棧中分配的,所以是線程安全的

          public void savebuy(String name,String product, int quantity)
          {
                
          }

          調用方式改為:

          <% 
          String name 
          String product; 
          long quantity; 
          name
          =request.getParameter("name"); 
          product
          =request.getParameter("product"); 
          quantity
          =request.getParameter("quantity"); 
          savebuy(name,product,quantity) 
          %> 

          如果savebuy的參數很多,或這些數據要在很多地方用到,也可聲明一個類,并用他做參數,如:

          public class buyinfo
          {
                String name;
                String product;
                
          long quantity;
          }
           
          public void savebuy(buyinfo info)
          {
                
          }

           調用方式改為:

          <% 
          buyinfo userbuy 
          = new buyinfo(); 

          userbuy.name
          =request.getParameter("name"); 
          userbuy.product
          =request.getParameter("product"); 
          userbuy.quantity
          =request.getParameter("quantity"); 
          savebuy(userbuy); 
          %>

           所以最好是用3,因為1,2會降低系統的性能. 多線程問題一般只有在在大并發量訪問時,才有可能出現,并且很難重復出現,所以應在編程時就時刻注意。


          轉CSDN

          posted on 2007-05-24 11:14 cheng 閱讀(278) 評論(0)  編輯  收藏 所屬分類: JSP/Servlet
          主站蜘蛛池模板: 灵台县| 河东区| 香河县| 城市| 桦南县| 奉化市| 长白| 麻阳| 余干县| 三穗县| 永宁县| 乌兰浩特市| 连江县| 佛山市| 桑植县| 扬州市| 阿拉善左旗| 富裕县| 卢湾区| 江孜县| 河间市| 巫山县| 永登县| 宁海县| 洛川县| 桐柏县| 镶黄旗| 扶绥县| 大埔区| 娄底市| 府谷县| 大丰市| 东兰县| 恭城| 台安县| 施甸县| 彭阳县| 渭南市| 克什克腾旗| 南阳市| 九江县|