前兩天律姨,有個(gè)人問(wèn)我“servlet是線程安全的嗎?“臼疫,我卻很難給出一個(gè)很具體清晰的回答择份,今天重新整理一下思路,也復(fù)習(xí)一下那些被扔回給老師的理論烫堤。
servlet是線程安全的嗎荣赶?
這個(gè)問(wèn)題,在網(wǎng)上沒(méi)有看到一個(gè)確切的答案鸽斟,所以我們來(lái)分析一下:
首先什么是線程安全拔创?
引用概念:如果你的代碼所在的進(jìn)程中有多個(gè)線程在同時(shí)運(yùn)行,而這些線程可能會(huì)同時(shí)運(yùn)行這段代碼富蓄。如果每次運(yùn)行結(jié)果和單線程運(yùn)行的結(jié)果是一樣的剩燥,而且其他的變量的值也和預(yù)期的是一樣的,就是線程安全的立倍。
那么我們都知道servlet是多線程的灭红,同時(shí)一個(gè)servlet實(shí)現(xiàn)類(lèi)只會(huì)有一個(gè)實(shí)例對(duì)象,也就是它是Singleton的,所以多個(gè)線程是可能會(huì)訪問(wèn)同一個(gè)servlet實(shí)例對(duì)象的口注。
每個(gè)線程都會(huì)為數(shù)據(jù)實(shí)例對(duì)象開(kāi)辟單獨(dú)的引用比伏,那么servlet會(huì)是線程安全的嗎?
要判斷是否是線程安全疆导,我們需要知道線程安全問(wèn)題是由什么引起的赁项。
搜索得到答案:線程安全問(wèn)題都是由全局變量及靜態(tài)變量引起的。
看到這個(gè)答案澈段,突然想起很多年前調(diào)查過(guò)的一個(gè)bug, 那時(shí)我們系統(tǒng)中遺留的代碼中寫(xiě)了很多全局變量悠菜,有一次發(fā)布后,客戶(hù)反饋败富,當(dāng)有多人同時(shí)進(jìn)行某個(gè)操作時(shí)悔醋,我們的數(shù)據(jù)出了問(wèn)題,那時(shí)我們調(diào)查后的結(jié)果就是:多人同步操作時(shí)兽叮,有些全局變量的值不對(duì)了芬骄,之后我們專(zhuān)門(mén)設(shè)一個(gè)人花了很多工夫來(lái)將所有全局變量都改成了局部變量了,并且項(xiàng)目要求以后不允許用全局變量鹦聪。原來(lái)那時(shí)侯我就已經(jīng)碰到過(guò)線程不安全的情況了啊账阻,不過(guò)處理方式或者不用全局,或者加入同步泽本,若加入同步同時(shí)也要考慮一下對(duì)程序效率會(huì)不會(huì)產(chǎn)生影響淘太。
由此可知,servlet是否線程安全是由它的實(shí)現(xiàn)來(lái)決定的,如果它內(nèi)部的屬性或方法會(huì)被多個(gè)線程改變蒲牧,它就是線程不安全的撇贺,反之,就是線程安全的冰抢。
在網(wǎng)上找到一個(gè)例子松嘶,如下:
public class TestServlet extends HttpServlet {
private int count = 0;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().println("");
response.getWriter().println(this + " ==> ");
response.getWriter().println(Thread.currentThread() + ":
");
for(int i=0;i<5;i++){
response.getWriter().println("count = " + count + "
");
try {
Thread.sleep(1000);
count++;
} catch (Exception e) {
e.printStackTrace();
}
}
response.getWriter().println("");
}
}
當(dāng)同時(shí)打開(kāi)多個(gè)瀏覽器,輸入http://localhost:8080/ServletTest/TestServlet時(shí)挎扰,他們顯示的結(jié)果不同喘蟆,這就說(shuō)明了對(duì)于屬性count來(lái)說(shuō),它是線程不安全的鼓鲁,
為了解決這個(gè)問(wèn)題,將代碼重構(gòu)港谊,如下:
public class TestServlet extends HttpServlet {
private int count = 0;
private String synchronizeStr = "";
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().println("");
response.getWriter().println(this + " ==> ");
response.getWriter().println(Thread.currentThread() + ":
");
synchronized (synchronizeStr){
for(int i=0;i<5;i++){
response.getWriter().println("count = " + count + "
");
try {
Thread.sleep(1000);
count++;
} catch (Exception e) {
e.printStackTrace();
}
}
}
response.getWriter().println("");
}
}
原文地址:
http://www.cnblogs.com/itTeacher/archive/2012/11/14/2769822.html