編寫線程安全的JSP程序
作者:徐春金
JSP默認是以多線程方式執(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中可能用的的變量說明如下:
- 實例變量
實例變量是在堆中分配的,并被屬于該實例的所有線程共享,所以不是線程安全的. - JSP系統(tǒng)提供的8個類變量
JSP中用到的OUT,REQUEST,RESPONSE,SESSION,CONFIG,PAGE,PAGECONXT是線程安全的,APPLICATION在整個系統(tǒng)內(nèi)被使用,所以不是線程安全的. - 局部變量
局部變量在堆棧中分配,因為每個線程都有它自己的堆棧空間,所以是線程安全的. - 靜態(tài)類
靜態(tài)類不用被實例化,就可直接使用,也不是線程安全的. - 外部資源:
在程序中可能會有多個線程或進程同時操作同一個資源(如:多個線程或進程同時對一個文件進行寫操作).此時也要注意同步問題.
二、下面的例子存在的多線程問題:
<%@ 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());
}
}
}
%>
三、解決方法
- 采用單線程方式
在該JSP文件中加上: <%@ page isThreadSafe="false" %>,使它以單線程方式執(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)
{
......
}
調(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)在編程時就時刻注意。
相關(guān)文章
servlet+JSP+mysql實現(xiàn)文件上傳的方法
這篇文章主要介紹了servlet+JSP+mysql實現(xiàn)文件上傳的方法,涉及JSP文件傳輸與判斷及數(shù)據(jù)庫操作的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-11-11JSP動態(tài)生成驗證碼存儲在session作用范圍內(nèi)
下面的代碼實現(xiàn)的功能:寫一個JSP頁,動態(tài)生成一個驗證碼,存儲在session作用范圍內(nèi),并以圖像形式返回給客戶端顯示2014-09-09jsp+ajax實現(xiàn)無刷新(鼠標(biāo)離開文本框即驗證用戶名)實現(xiàn)思路
jsp+ajax實現(xiàn)無刷新,鼠標(biāo)離開文本框即驗證用戶名,很方便的功能,感興趣的朋友可以了解下,或許對你學(xué)習(xí)ajax無刷新有所幫助2013-01-01