Servlet线程安全
概述?
在探討java線程安全前,讓我們先簡要介紹一下Java語言。?
任何語言,如C++,C#,Java,它們都有相通之處,特別是語法,但如果有人問你,Java語言的核心是什么?類庫?關鍵字?語法?似乎都不 是。Java語言的核心,也就是Sun始終不愿意開源的東西:Java虛擬機的實現(不過sun公開了其Java虛擬機規范),也就有了BEA的 JRockit,IBM的Jikes,Sun的Hotspot。?
Java的核心有兩點,Java類加載(Java Class Loader)和Java內存管理,它們具體體現在Java類庫的以下幾個類:?
java.lang.ClassLoader(java.lang.Class):我們調用的類,包括其接口和超類,import的類是怎么被Java虛擬機載入的?為什么static的字段在servlet容器里面可以一直生存下去(Spring容器中)??
java.lang.Thread(java.lang.ThreadLocal):垃圾回收是怎么進行的(垃圾回收線程)?我們的程序是怎么退出的??
java.lang.refelect.Proxy(java.lang.refelect.Method):為什么Tomcat、 Tapestry、Webwork、Spring等容器和框架可以通過配置文件來調用我們寫的類?Servlet規范、JSF規范、EJB規范、JDBC 規范究竟是怎么回事?為什么它們幾乎都是一些接口,而不是具體類??
Servlet線程安全?
在Java的server side開發過程中,線程安全(Thread Safe)是一個尤為突出的問題。因為容器,如Servlet、EJB等一般都是多線程運行的。雖然在開發過程中,我們一般不考慮這些問題,但診斷問題 (Robust),程序優化(Performance),我們必須深入它們。?
什么是線程安全??
在Java里,線程安全一般體現在兩個方面:?
1、多個thread對同一個java實例的訪問(read和modify)不會相互干擾,它主要體現在關鍵字synchronized。如 ArrayList和Vector,HashMap和Hashtable(后者每個方法前都有synchronized關鍵字)。如果你在 interator一個List對象時,其它線程remove一個element,問題就出現了。?
2、每個線程都有自己的字段,而不會在多個線程之間共享。它主要體現在java.lang.ThreadLocal類,而沒有Java關鍵字支持,如像static、transient那樣。?
一個普遍的疑問,我們的Servlet中能夠像JavaBean那樣declare instance或static字段嗎?如果不可以?會引發什么問題??
答案是:不可以。下面以實例講解:?
首先,寫一個普通的Servlet,里面有instance字段count:
web.xml? >>
<servlet><servlet-name>SimpleServlet</servlet-name><servlet-class>servlet.SimpleServlet</servlet-class> </servlet> <servlet-mapping><servlet-name>SimpleServlet</servlet-name><url-pattern>/SimpleServlet</url-pattern> </servlet-mapping>?
?
SimpleServlet? >>
public class SimpleServlet extends HttpServlet {private int counter = 0; @Overrideprotected void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.getWriter().println("<HTML><BODY>");response.getWriter().println(this + " ==> ");response.getWriter().println(Thread.currentThread() + ": <br>"); for(int c=0;c<10;c++){response.getWriter().println("Counter = " + counter + "");try {Thread.sleep(1000); counter++; } catch (Exception e) {e.printStackTrace();}}response.getWriter().println("</BODY></HTML>");}}?
test.html? >>
<html> <body> <table> <tr> <td><iframe src="SimpleServlet" name="servlet1" height="200%"> </iframe ></td> </tr> </table> </body> </html>?
test.html的內容如上所示,打開3個IE瀏覽器,同時在瀏覽器中輸入:
a: http://localhost:8080/ServletTest/SimpleServlet b: http://localhost:8080/ServletTest/SimpleServlet c: http://localhost:8080/ServletTest/SimpleServlet
? 測試結果如下:
?????????
? 我們會發現三點:?
1、Servlet是一個單例對象(Singleton),因為我們看到多次請求的this指針所有打印出來的hashCode值都相同。
2、servlet在不同的線程(線程池)中運行,如http-8080-1,http-8080-2,http-8080-3 等輸出值可以明顯區分出不同的線程執行了不同一段Servlet邏輯代碼。
3、count變量在不同的線程中共享,而且它的值被不同的線程修改,輸出時已經不是順序輸出。也就是說,其他的線程會篡改當前線程中實例變量的值,針對這些對象的訪問不是線程安全的。
上面的結果,違反了線程安全的兩個方面。?
那么,我們怎樣保證按照我們期望的結果運行呢?首先,我想保證產生的count都是順序執行的。?
我們將Servlet代碼重構如下:
?
public class SimpleServlet extends HttpServlet {private int counter = 0; private String mutex = ""; @Overrideprotected void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.getWriter().println("<HTML><BODY>");response.getWriter().println(this + " ==> ");response.getWriter().println(Thread.currentThread() + ": <br>"); synchronized (mutex){for(int c=0;c<10;c++){response.getWriter().println("Counter = " + counter + "<BR>");try {Thread.sleep(1000); counter++; } catch (Exception e) {e.printStackTrace();}}}response.getWriter().println("</BODY></HTML>");}}?
這符合要求,輸出都是按順序的,這正式synchronized的含義。
附帶說一下,我現在synchronized的是一個字符串變量mutex,不是this對象,這主要是從performance和 Scalability考慮。Synchronized用在this對象上,會帶來嚴重的可伸縮性的問題(Scalability),所有的并發請求都要排隊!
?
轉載:http://www.cnblogs.com/gw811/archive/2012/09/07/2675294.html
轉載于:https://www.cnblogs.com/go-skill/p/6078082.html
總結
以上是生活随笔為你收集整理的Servlet线程安全的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 18.虚拟机linux上网问题
- 下一篇: 舞钢市汽车学校?