編寫執行緒安全的JSP應用程式

技術豪門發表於2020-12-29

本篇文章由 泉州SEO www.234yp.com 整理髮布,jsp內建物件 www.234yp.com/Article/176239.html 謝謝合作!
jsp內建物件

  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.*
  " %>

  <%
  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());
  }
  }
  }
  %>

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

  三、解決方法

  採用單執行緒方式

  在該JSP檔案中加上: ,使它以單執行緒方式執行,這時,仍然只有一個例項,所有客戶端的請求以序列方 式執行。這樣會降低系統的效能。

  對函式savebuy()加synchronized進行執行緒同步,該JSP仍然以多執行緒方式執行,但也會降低系統的效能:

  public synchronized void savebuy()
  {
  ......
  } 

  採用區域性變數代替例項變數,函式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會降低系統的效能。

  多執行緒問題一般只有在在大併發量訪問時,才有可能出現,並且很難重複出現,所以應在程式設計時就時刻注意。


關於更多jsp內建物件內容,可以收藏本網頁。
上海財經

相關文章