servlet之模板方法和多線程,servlet模板多線程

來源:互聯網
上載者:User

servlet之模板方法和多線程,servlet模板多線程

接觸了一小段時間的servlet,下面就總結一下關於servlet的兩個方面的知識,一個是模板方法的應用。另外一個是servlet多線程產生的原因。

1. 模板方法設計模式

         定義一個操作中的演算法的骨架,而將步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可重定義演算法的某些特定步驟。

        

 

2. Servlet中模板方法的應用

     模板方法在servlet中的應用的類圖

   

           當用戶端請求一個servlet的時候首先被調用的是service方法。Service方法就是定義骨架的方法,在service方法中會根據HTTP請求的類型(GET,POST還是其他)來調用具體的doGet和doPost等方法;即實際的處理委派給了doGet和doPost等方法,這些子類的方法來最終處理瀏覽器的請求。下面是HttpServlet對service方法的具體實現。

  

protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException    {String method = req.getMethod();if (method.equals(METHOD_GET)) {    long lastModified = getLastModified(req);    if (lastModified == -1) {// servlet doesn't support if-modified-since, no reason// to go through further expensive logicdoGet(req, resp);    } else {long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);if (ifModifiedSince < (lastModified / 1000 * 1000)) {    // If the servlet mod time is later, call doGet()                    // Round down to the nearest second for a proper compare                    // A ifModifiedSince of -1 will always be less    maybeSetLastModified(resp, lastModified);    doGet(req, resp);} else {    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);}    }} else if (method.equals(METHOD_HEAD)) {    long lastModified = getLastModified(req);    maybeSetLastModified(resp, lastModified);    doHead(req, resp);} else if (method.equals(METHOD_POST)) {    doPost(req, resp);    } else if (method.equals(METHOD_PUT)) {    doPut(req, resp);    } else if (method.equals(METHOD_DELETE)) {    doDelete(req, resp);    } else if (method.equals(METHOD_OPTIONS)) {    doOptions(req,resp);    } else if (method.equals(METHOD_TRACE)) {    doTrace(req,resp);    } else {    //    // Note that this means NO servlet supports whatever    // method was requested, anywhere on this server.    //    String errMsg = lStrings.getString("http.method_not_implemented");    Object[] errArgs = new Object[1];    errArgs[0] = method;    errMsg = MessageFormat.format(errMsg, errArgs);        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);}    }


3. servlet並不是嚴格的按照模板方法來設計的

    我們常說具體問題具體分析,在這裡也是。servlet 講模板方法的精髓應用到了,但是卻沒有完全按照模板方法設計。

      3.1 子類可以重寫service()方法

             模板方法模式是通過把不變的行為搬移到超類,去除了子類中的重複代碼。所以超類中的模板方法一般情況下是不會被重寫的。模板方法允許子類重新定義演算法的某些     步驟,而不改變演算法的結構。但是在servlet中的service方法中是可以被子類重寫的。當子類重寫了service方法之後就破壞掉了原本定義好的模板方法。

 

       3.2 doGet和doPost方法有預設的實現

               在HttpServlet類中對於這兩個被子類具體實現的方式是有實現的。下面是HttpServlet對於這兩個實現的代碼

     

 protected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException    {String protocol = req.getProtocol();String msg = lStrings.getString("http.method_post_not_supported");if (protocol.endsWith("1.1")) {    resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);} else {    resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);}    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException    {String protocol = req.getProtocol();String msg = lStrings.getString("http.method_get_not_supported");if (protocol.endsWith("1.1")) {    resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);} else {    resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);}    }

 這些說明在使用設計模式的時候並不是生搬硬套,而是根據具體的情況靈活變動。但是其本質是不變的。


4.  為什麼會出現安全執行緒問題

      在學習servlet過程中一直聽到的一個問題就是線程問題,學習的資料中提到servlet是多線程,不安全的。

      servlet是由web容器管理的,當請求這個servlet的時候,web容器會根據web.xml中的配置執行個體化這個servlet。當再次請求這個servlet的時候不會再執行個體化此servlet而是多線程的使用第一次請求的時候執行個體化的servlet。也就是一個servlet只執行個體化一次。

      當面對多個請求的時候web容器就會使用多線程來處理這些請求。下面的圖形是servlet多線程的結構圖形

     

        可以看出,當容器收到一個請求servlet的請求的時候會從線程池中分出一個背景工作執行緒來處理這個請求,當有另外一個請求的時候會從線程池中分出另外一個背景工作執行緒來處理這個請求;所以如果多個使用者同時請求同一個servlet,那麼在容器中就會出現一個servlet對象的service方法並發執行。多線程是共用資源的,當他們並發執行的時候就很有可能出現訪問資源衝突問題。

        這種處理請求的方式就是我們經常說的單一實例多線程的處理方式。

      下面是自己尋找到的一個作者:http://blog.csdn.net/zljjava/article/details/6887266從記憶體的角度來分析的servlet的多線程問題。如果有興趣的話可以看看。

       從記憶體中看一下這個問題可以總結下面的兩種圖形,其中一張是我們都知道JMM模型圖


        

      另外一張是多個使用者請求同一個servlet的多線程執行的過程是:

 

        主記憶體中的執行個體變數是在多個線程之間共用的,每個線程在自己的背景工作執行緒中拷貝自己需要的執行個體變數到自己的緩衝中。就如同上面圖形中的A,當線程1修改了A,但是線程2中的A還是主存中的樣子,並沒有馬上同步到線程2和線程3中就會出現安全執行緒問題。


5. 總結

         對於servlet的單一實例多線程問題知道的原因就可以對症下藥的找解決方案了。主要是針對變數要注意。對於模板方法可以看到我們的應用很多但是也要注意活學活用。



servlet多線程

1.javax.servlet.SingleThreadModel介面是一個標識介面,如果一個Servlet類實現了這個介面,那麼Servlet容器將保證在同一個時刻只有一個線程可以在給定的servlet執行個體的service方法中執行。而將其他所有請求進行排隊。
伺服器可以使用多個執行個體來處理請求,代替單個執行個體的請求排隊帶來的效益問題。伺服器建立一個Servlet類的多個Servlet執行個體組成的執行個體池,對於每個請求分配Servlet執行個體進行響應處理,之後放回到執行個體池中等待下此請求。這樣就造成並發訪問的問題。
此時,局部變數(欄位)也是安全的,但對於全域變數和共用資料是不安全的,需要進行同步處理。而對於這樣多執行個體的情況SingleThreadModel介面並不能解決並發訪問問題。因此,不建議實現SingleThreadModel介面,因為它在servlet規範中已經被廢棄了。
2.使用同步塊Synchronized,防止可能非同步呼叫的代碼塊。這意味著線程需要排隊處理。在使用同板塊的時候要儘可能的縮小同步代碼的範圍,不要直接在sevice方法和回應程式法上使用同步,這樣會嚴重影響效能。
ServletContext是可以多線程同時讀/寫屬性的,線程是不安全的。要對屬性的讀寫進行同步處理或者進行深度Clone()。
所以在Servlet上下文中儘可能少量儲存會被修改(寫)的資料,可以採取其他方式在多個Servlet中共用,比方我們可以使用單例模式來處理共用資料。
HttpSession(線程是不安全的)
HttpSession對象在使用者會話期間存在,只能在處理屬於同一個Session的請求的線程中被訪問,因此Session對象的屬性訪問理論上是安全執行緒的。
當使用者開啟多個同屬於一個進程的瀏覽器視窗,在這些視窗的訪問屬於同一個Session,會出現多次請求,需要多個背景工作執行緒來處理請求,可能造成同時多線程讀寫屬性。
這時我們需要對屬性的讀寫進行同步處理:使用同步塊Synchronized和使用讀/寫器來解決。
對於每一個請求,ServletRequest由一個背景工作執行緒來執行,都會建立有一個新的ServletRequest對象,所以ServletRequest對象只能在一個線程中被訪問。所以ServletRequest是安全執行緒的。ServletRequest對象在service方法的範圍內是有效,不要試圖在service方法結束後仍然儲存請求對象的引用。
對於集合, 使用安全執行緒的Vector代替ArrayList,使用Hashtable代替HashMap。
不要在Servlet中建立自己的線程來完成某個功能。
Servlet本身就是多線程的,在Servlet中再建立線程,將導致執行情況複雜化,出現多安全執行緒問題。
,在多個servlet中對外部對象(比方檔案)進行修改操作一定要加鎖,做到互斥的訪問
對於為什麼要在doget方法裡另上同步塊,就是因為解決:當a,b同時訪問時,如果a比b稍慢一些就會出現這樣的情況,a頁面空白,而b頁面出現了服務端返回給a的結果,假如是比較敏感的個人資訊不能讓他人知道 的,而這種情況就會出現嚴重的安全問題,使用同步塊並加鎖可以做到a,b訪問時兩者的資訊不會被對方及第三方知道!
 
servlet 怎實現多線程

不知道你問這個具體是什麼意思。。
其實就Tomcat來說,調用同一個servlet已經實現了多線程,就是說,在servlet之前,CGI時代,每一個使用者訪問都會產生一個進程,後來發展到servlet,每一個使用者訪問,只會產生一個servlet線程
這樣的話,就沒必要自己再實現多線程了^^
參考資料:自己思考
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.