weidagang2046的專欄

          物格而后知致
          隨筆 - 8, 文章 - 409, 評論 - 101, 引用 - 0
          數(shù)據(jù)加載中……

          編寫線程安全的JSP程序

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


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


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


          實例變量

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

          JSP系統(tǒng)提供的8個類變量

          JSP中用到的OUT,REQUEST,RESPONSE,SESSION,CONFIG,PAGE,PAGECONXT是線程安全的,APPLICATION在整個系統(tǒng)內被使用,所以不是線程安全的.

          局部變量

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

          靜態(tài)類

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

          外部資源:

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

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



          <%@ page import="

          Java x.naming.*,

          java.util.*,

          java.sql.*,

          Web logic.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í)行是會對應多個機器指令,在任何時候都可能因系統(tǒng)調度而轉入睡眠狀態(tài),讓其他的線程繼續(xù)執(zhí)行.如果線程A在執(zhí)行到(1)的時候轉入睡眠狀態(tài),線程B開始執(zhí)行并改變QUANTITY的值,那么當又到A執(zhí)行時,它會從調用savebuy()函數(shù)開始執(zhí)行,這樣它保存到表中的QUANTITY是被線程B改過的值,那么線程A對應的用戶所實際購買的數(shù)量與保持到表中的數(shù)據(jù)不一致.這是個很嚴重的問題.

          三、解決方法


          采用單線程方式

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


          對函數(shù)savebuy()加synchronized進行線程同步,該JSP仍然以多線程方式執(zhí)行,但也會降低系統(tǒng)的性能

          public synchronized void savebuy()

          {

          ......

          }


          采用局部變量代替實例變量,函數(shù)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的參數(shù)很多,或這些數(shù)據(jù)要在很多地方用到,也可聲明一個類,并用他做參數(shù),如:


          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會降低系統(tǒng)的性能.

          多線程問題一般只有在在大并發(fā)量訪問時,才有可能出現(xiàn),并且很難重復出現(xiàn),所以應在編程時就時刻注意。

          from: http://java.ccidnet.com/art/3737/20030321/530503_1.html

          posted on 2006-10-30 17:48 weidagang2046 閱讀(238) 評論(0)  編輯  收藏 所屬分類: Java

          主站蜘蛛池模板: 大方县| 松阳县| 霍邱县| 宝鸡市| 兰西县| 仙居县| 色达县| 杨浦区| 章丘市| 巴马| 福贡县| 天镇县| 纳雍县| 旬邑县| 鸡泽县| 河北省| 固镇县| 兰考县| 南充市| 宜黄县| 勃利县| 皮山县| 同德县| 虞城县| 肥城市| 余江县| 神池县| 张家界市| 娄底市| 松阳县| 阆中市| 太仆寺旗| 介休市| 高邑县| 黑水县| 临泽县| 盐山县| 滕州市| 云安县| 德格县| 麻栗坡县|