1. 程式人生 > >面試題,Servlet 執行緒安全嗎?

面試題,Servlet 執行緒安全嗎?

Servlet的工作原理:

首先客戶傳送一個請求,Servlet是呼叫service()方法對請求進行響應的,通過原始碼可見,service()方

法中對請求的方式進行了匹配,選擇呼叫doGet,doPost等這些方法,然後再進入對應的方法中呼叫邏輯層的方法,實現對客戶的響應。在Servlet介面和GenericServlet中是沒doGet,doPost等等這些方法的,HttpServlet中定義了這些方法,但是都是返回error資訊,所以,我們每次定義一個Servlet的時候,都必須實現doGet或doPost等這些方法。

  每一個自定義的Servlet都必須實現Servlet的介面,Servlet介面中定義了五個方法,其中比較重要的三個方法涉及到Servlet的生命週期,分別是上文提到的init(),service(),destroy()方法。GenericServlet是一個通用的,不特定於任何協議的Servlet,它實現了Servlet介面。而HttpServlet繼承於GenericServlet,因此HttpServlet也實現了Servlet介面。所以我們定Servlet的時候只需要繼承HttpServlet即可。

  Servlet介面和GenericServlet是不特定於任何協議的,而HttpServlet是特定於HTTP協議的類,所以HttpServlet中實現了service()方法,並將請求ServletRequest,ServletResponse強轉為HttpRequest和HttpResponse。在Servlet整個生命週期中是由Tomcat來維護的,當客戶端第一次發起請求的時候,會根據web.xml檔案中的配置例項化一個Servlet,而在以後客戶端的每一次請求都會使用該例項來處理後續的工作,知道Tomcat停止該專案,這個Servlet才會被銷燬,所佔用的資源才會釋放。

  當客戶端發來多個請求的時候,Servlet將採用多執行緒來解決這樣的併發,而在Tomcat本身也維護了一個執行緒池來處理併發。執行緒池實際上是等待執行程式碼的一組執行緒叫做工作組執行緒(Worker Thread),Tomcat容器使用一個排程執行緒來管理工作組執行緒(Dispatcher Thead)。

Servlet執行緒安全問題很大部分是由例項變數造成的,只要在Servlet裡面的任何方法裡面都不使用例項變數,那麼該Servlet就是執行緒安全的。

有什麼方法能夠解決這個問題呢?答案是將例項變數程式設計區域性變數,

為什麼區域性變數為什麼不會被共享呢?

 多執行緒下每個執行緒對區域性變數都會有自己的一份copy,這樣對區域性變數的修改只會影響到自己的copy而不會對別的執行緒產生影響,執行緒安全的。

Java 記憶體模型中,方法中的臨時變數是在棧上分配空間,而且每個執行緒都有自己私有的棧空間,所以它們不會影響執行緒的安全。

但是對於例項變數來說,由於servlet在Tomcat中是以單例模式存在的,所有的執行緒共享例項變數。多個執行緒對共享資源的訪問就造成了執行緒不安全問題。