隨筆 - 6  文章 - 0  trackbacks - 0
          <2025年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          常用鏈接

          留言簿(2)

          隨筆分類

          文章分類

          好友

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

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

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

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

          1. 實例變量
            實例變量是在堆中分配的,并被屬于該實例的所有線程共享,所以不是線程安全的.
          2. JSP系統(tǒng)提供的8個類變量
            JSP中用到的OUT,REQUEST,RESPONSE,SESSION,CONFIG,PAGE,PAGECONXT是線程安全的,APPLICATION在整個系統(tǒng)內(nèi)被使用,所以不是線程安全的.
          3. 局部變量
            局部變量在堆棧中分配,因為每個線程都有它自己的堆棧空間,所以是線程安全的.
          4. 靜態(tài)類
            靜態(tài)類不用被實例化,就可直接使用,也不是線程安全的.
          5. 外部資源:
            在程序中可能會有多個線程或進程同時操作同一個資源(如:多個線程或進程同時對一個文件進行寫操作).此時也要注意同步問題.

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

          <%@ 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()
          {
              /*進行數(shù)據(jù)庫操作,把數(shù)據(jù)保存到表中*/
              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());
                  }
              }
          }
          %>

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

          三、解決方法

          1. 采用單線程方式
            在該JSP文件中加上: <%@ page isThreadSafe="false" %>,使它以單線程方式執(zhí)行,這時,仍然只有一個實例,所有客戶端的請求以串行方 式執(zhí)行。這樣會降低系統(tǒng)的性能.
          2. 對函數(shù)savebuy()加synchronized進行線程同步,該JSP仍然以多線程方式執(zhí)行,但也會降低系統(tǒng)的性能
            public synchronized void savebuy()
            {
                   ......
            }
          3. 采用局部變量代替實例變量,函數(shù)savebuy()聲明如下:
            因為在savebuy()中使用的是傳給他的形參,是在堆棧中分配的,所以是線程安全的.
            public void savebuy(String name,String product, int quantity)
            {
                  ......
            }

            調(diào)用方式改為:
            <%
            String name
            String product;
            long quantity;

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

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

            public class buyinfo
            {
                  String name;
                  String product;
                  long quantity;
            }

            public void savebuy(buyinfo info)
            {
                  ......
            }

            調(diào)用方式改為:
            <%
            buyinfo userbuy = new buyinfo();

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

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

          posted on 2006-03-02 14:22 badboy 閱讀(176) 評論(0)  編輯  收藏 所屬分類: Java基礎(chǔ)

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 日照市| 南平市| 大同市| 晋城| 浑源县| 红桥区| 天水市| 城口县| 本溪市| 莱芜市| 昌宁县| 灵寿县| 信宜市| 曲靖市| 嘉义市| 海林市| 铜山县| 昆山市| 冀州市| 博客| 岳池县| 四川省| 福州市| 厦门市| 南投市| 历史| 大渡口区| 东源县| 扬州市| 潼关县| 石阡县| 武义县| 靖远县| 宝山区| 自贡市| 石柱| 吴桥县| 临海市| 成武县| 定安县| 丁青县|