<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 104,  comments - 34,  trackbacks - 0

    Servlet體系結(jié)構(gòu)是建立在Java多線程機制之上的,它的生命周期是由Web容器負責(zé)的。當(dāng)客戶端第一次請求某個Servlet時,Servlet容器將會根據(jù)web.xml配置文件實例化這個Servlet類。當(dāng)有新的客戶端請求該Servlet時,一般不會再實例化該Servlet類,也就是有多個線程在使用這個實例。 這樣,當(dāng)兩個或多個線程同時訪問同一個Servlet時,可能會發(fā)生多個線程同時訪問同一資源的情況,數(shù)據(jù)可能會變得不一致。所以在用Servlet構(gòu)建的Web應(yīng)用時如果不注意線程安全的問題,會使所寫的Servlet程序有難以發(fā)現(xiàn)的錯誤。

    實例變量不正確的使用是造成Servlet線程不安全的主要原因。下面針對該問題給出了三種解決方案并對方案的選取給出了一些參考性的建議。

      1、實現(xiàn) SingleThreadModel 接口

      該接口指定了系統(tǒng)如何處理對同一個Servlet的調(diào)用。如果一個Servlet被這個接口指定,那么在這個Servlet中的service方法將不會有兩個線程被同時執(zhí)行,當(dāng)然也就不存在線程安全的問題。這種方法只要將前面的Concurrent Test類的類頭定義更改為:

    Public class Concurrent Test extends HttpServlet implements SingleThreadModel {
         …………
    }
      2、同步對共享數(shù)據(jù)的操作

      使用synchronized 關(guān)鍵字能保證一次只有一個線程可以訪問被保護的區(qū)段,在本論文中的Servlet可以通過同步塊操作來保證線程的安全。同步后的代碼如下:

    …………
    Public class Concurrent Test extends HttpServlet { …………
    Username = request.getParameter ("username");
    Synchronized (this){
    Output = response.getWriter ();
    Try {
    Thread. Sleep (5000);
    } Catch (Interrupted Exception e){}
    output.println("用戶名:"+Username+"
    ");
    }
    }
    }
      3、避免使用實例變量

      本實例中的線程安全問題是由實例變量造成的,只要在Servlet里面的任何方法里面都不使用實例變量,那么該Servlet就是線程安全的。

      修正上面的Servlet代碼,將實例變量改為局部變量實現(xiàn)同樣的功能,代碼如下:

    ……
    Public class Concurrent Test extends HttpServlet {public void service (HttpServletRequest request, HttpServletResponse
    Response) throws ServletException, IOException {
    Print Writer output;
    String username;
    Response.setContentType ("text/html; charset=gb2312");
    ……
    }
    }
      對上面的三種方法進行測試,可以表明用它們都能設(shè)計出線程安全的Servlet程序。但是,如果一個Servlet實現(xiàn)了SingleThreadModel接口,Servlet引擎將為每個新的請求創(chuàng)建一個單獨的Servlet實例,這將引起大量的系統(tǒng)開銷。SingleThreadModel在Servlet2.4中已不再提倡使用;同樣如果在程序中使用同步來保護要使用的共享的數(shù)據(jù),也會使系統(tǒng)的性能大大下降。這是因為被同步的代碼塊在同一時刻只能有一個線程執(zhí)行它,使得其同時處理客戶請求的吞吐量降低,而且很多客戶處于阻塞狀態(tài)。另外為保證主存內(nèi)容和線程的工作內(nèi)存中的數(shù)據(jù)的一致性,要頻繁地刷新緩存,這也會大大地影響系統(tǒng)的性能。所以在實際的開發(fā)中也應(yīng)避免或最小化 Servlet 中的同步代碼;在Serlet中避免使用實例變量是保證Servlet線程安全的最佳選擇。從Java 內(nèi)存模型也可以知道,方法中的臨時變量是在棧上分配空間,而且每個線程都有自己私有的棧空間,所以它們不會影響線程的安全。


    --------------------------------------------------------------------------------

    補充:

    servlet存在的多線程問題
    實例變量:   實例變量是在堆中分配的,并被屬于該實例的所有線程共享,所以不是線程安全的.
    JSP系統(tǒng)提供的8個類變量:
    JSP中用到的OUT,REQUEST,RESPONSE,SESSION,CONFIG,PAGE,PAGECONXT是線程安全的,APPLICATION在整個系統(tǒng)內(nèi)被使用,所以不是線程安全的.
    局部變量:   局部變量在堆棧中分配,因為每個線程都有它自己的堆棧空間,所以是線程安全的.
    靜態(tài)類:       靜態(tài)類不用被實例化,就可直接使用,也不是線程安全的.
    外部資源:   在程序中可能會有多個線程或進程同時操作同一個資源(如:多個線程或進程同時對一個文件進行寫操作).

    此時也要注意同步問題. 使它以單線程方式執(zhí)行,這時,仍然只有一個實例,所有客戶端的請求以串行方式執(zhí)行。這樣會降低系統(tǒng)的性能
    對于存在線程不安全的類,如何避免出現(xiàn)線程安全問題:
    1、采用synchronized同步。缺點就是存在堵塞問題。
    2、使用ThreadLocal(實際上就是一個HashMap),這樣不同的線程維護自己的對象,線程之間相互不干擾。

     


    --------------------------------------------------------------------------------


    ThreadLocal的設(shè)計
    首先看看ThreadLocal的接口:
    Object get() ; // 返回當(dāng)前線程的線程局部變量副本 protected Object
    initialValue(); // 返回該線程局部變量的當(dāng)前線程的初始值                   
    void set(Object value); // 設(shè)置當(dāng)前線程的線程局部變量副本的值
      ThreadLocal有3個方法,其中值得注意的是initialValue(),該方法是一個protected
    的方法,顯然是為了子類重寫而特意實現(xiàn)的。該方法返回當(dāng)前線程在該線程局部變量的初始
    值,這個方法是一個延遲調(diào)用方法,在一個線程第1次調(diào)用get()或者set(Object)時才執(zhí)行
    ,并且僅執(zhí)行1次。ThreadLocal中的確實實現(xiàn)直接返回一個null:
    protected Object initialValue() { return null; }
      ThreadLocal是如何做到為每一個線程維護變量的副本的呢?其實實現(xiàn)的思路很簡單,
    在ThreadLocal類中有一個Map,用于存儲每一個線程的變量的副本。比如下面的示例實現(xiàn):

    public class ThreadLocal
    {
     private Map values = Collections.synchronizedMap(new HashMap());
     public Object get()
     {
      Thread curThread = Thread.currentThread();
      Object o = values.get(curThread);
      if (o == null && !values.containsKey(curThread))
      {
       o = initialValue();
       values.put(curThread, o);
      }
      return o;
     }

     public void set(Object newValue)
     {
      values.put(Thread.currentThread(), newValue);
     }

     public Object initialValue()
     {
      return null;
     }
    }

      當(dāng)然,這并不是一個工業(yè)強度的實現(xiàn),但JDK中的ThreadLocal的實現(xiàn)總體思路也類似于此。
    ThreadLocal的使用
      如果希望線程局部變量初始化其它值,那么需要自己實現(xiàn)ThreadLocal的子類并重寫該
    方法,通常使用一個內(nèi)部匿名類對ThreadLocal進行子類化,比如下面的例子,SerialNum類
    為每一個類分配一個序號:
    public class SerialNum
    {
     // The next serial number to be assigned
     private static int nextSerialNum = 0;
     private static ThreadLocal serialNum = new ThreadLocal()
     {
      protected synchronized Object initialValue()
      {
       return new Integer(nextSerialNum++);
      }
     };

     public static int get()
     {
      return ((Integer) (serialNum.get())).intValue();
     }
    }

      SerialNum類的使用將非常地簡單,因為get()方法是static的,所以在需要獲取當(dāng)前線
    程的序號時,簡單地調(diào)用:

    int serial = SerialNum.get(); 即可。
      在線程是活動的并且ThreadLocal對象是可訪問的時,該線程就持有一個到該線程局部
    變量副本的隱含引用,當(dāng)該線程運行結(jié)束后,該線程擁有的所以線程局部變量的副本都將失
    效,并等待垃圾收集器收集。
    ThreadLocal與其它同步機制的比較
      ThreadLocal和其它同步機制相比有什么優(yōu)勢呢?ThreadLocal和其它所有的同步機制都
    是為了解決多線程中的對同一變量的訪問沖突,在普通的同步機制中,是通過對象加鎖來實
    現(xiàn)多個線程對同一變量的安全訪問的。這時該變量是多個線程共享的,使用這種同步機制需
    要很細致地分析在什么時候?qū)ψ兞窟M行讀寫,什么時候需要鎖定某個對象,什么時候釋放該
    對象的鎖等等很多。所有這些都是因為多個線程共享了資源造成的。ThreadLocal就從另一
    個角度來解決多線程的并發(fā)訪問,ThreadLocal會為每一個線程維護一個和該線程綁定的變
    量的副本,從而隔離了多個線程的數(shù)據(jù),每一個線程都擁有自己的變量副本,從而也就沒有
    必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時
    ,可以把不安全的整個變量封裝進ThreadLocal,或者把該對象的特定于線程的狀態(tài)封裝進
    ThreadLocal。
      由于ThreadLocal中可以持有任何類型的對象,所以使用ThreadLocal get當(dāng)前線程的值
    是需要進行強制類型轉(zhuǎn)換。但隨著新的Java版本(1.5)將模版的引入,新的支持模版參數(shù)
    的ThreadLocal<T>類將從中受益。也可以減少強制類型轉(zhuǎn)換,并將一些錯誤檢查提前到了編
    譯期,將一定程度地簡化ThreadLocal的使用。
    總結(jié)
        當(dāng)然ThreadLocal并不能替代同步機制,兩者面向的問題領(lǐng)域不同。同步機制是為了同
    步多個線程對相同資源的并發(fā)訪問,是為了多個線程之間進行通信的有效方式;而
    ThreadLocal是隔離多個線程的數(shù)據(jù)共享,從根本上就不在多個線程之間共享資源(變量)
    ,這樣當(dāng)然不需要對多個線程進行同步了。所以,如果你需要進行多個線程之間進行通信,
    則使用同步機制;如果需要隔離多個線程之間的共享沖突,可以使用ThreadLocal,這將極
    大地簡化你的程序,使程序更加易讀、簡潔。

    ThreadLocal常見用途:
    存放當(dāng)前session用戶
    存放一些context變量,比如webwork的ActionContext
    存放session,比如Spring hibernate orm的session


    例子:用 ThreadLocal 實現(xiàn)每線程 Singleton
            線程局部變量常被用來描繪有狀態(tài)“單子”(Singleton) 或線程安全的共享對象,或者是通過把不安全的整個變量封裝進 ThreadLocal,或者是通過把對象的特定于線程的狀態(tài)封裝進 ThreadLocal。例如,在與數(shù)據(jù)庫有緊密聯(lián)系的應(yīng)用程序中,程序的很多方法可能都需要訪問數(shù)據(jù)庫。在系統(tǒng)的每個方法中都包含一個 Connection 作為參數(shù)是不方便的 — 用“單子”來訪問連接可能是一個雖然更粗糙,但卻方便得多的技術(shù)。然而,多個線程不能安全地共享一個 JDBC Connection。如清單 3 所示,通過使用“單子”中的 ThreadLocal,我們就能讓我們的程序中的任何類容易地獲取每線程 Connection 的一個引用。這樣,我們可以認為 ThreadLocal 允許我們創(chuàng)建每線程單子。
    例:把一個 JDBC 連接存儲到一個每線程 Singleton 中
    public class ConnectionDispenser {
      private static class ThreadLocalConnection extends ThreadLocal {
               public Object initialValue() {
                      return DriverManager.getConnection(ConfigurationSingleton.getDbUrl());
               }
       }
        private ThreadLocalConnection conn = new ThreadLocalConnection();
        public static Connection getConnection() {
                return (Connection) conn.get();
       }
    }

    注意:
    理論上來說,ThreadLocal是的確是相對于每個線程,每個線程會有自己的ThreadLocal。但是上面已經(jīng)講到,一般的應(yīng)用服務(wù)器都會維護一套線程池。因此,不同用戶訪問,可能會接受到同樣的線程。因此,在做基于TheadLocal時,需要謹慎,避免出現(xiàn)ThreadLocal變量的緩存,導(dǎo)致其他線程訪問到本線程變量。

     

    本文來自CSDN博客,轉(zhuǎn)載請標明出處:http://blog.csdn.net/Explorering/archive/2006/10/11/1330744.aspx

    posted on 2009-09-08 15:50 末日風(fēng)情 閱讀(1094) 評論(0)  編輯  收藏 所屬分類: JSP基礎(chǔ)

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    <2009年9月>
    303112345
    6789101112
    13141516171819
    20212223242526
    27282930123
    45678910

    常用鏈接

    留言簿(4)

    隨筆分類

    隨筆檔案

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 韩国亚洲伊人久久综合影院| 久久亚洲sm情趣捆绑调教| 亚洲理论电影在线观看| 国产亚洲精品无码成人| 亚洲美女视频一区二区三区| www.亚洲成在线| 在线精品自拍亚洲第一区| 免费大片av手机看片| 18禁在线无遮挡免费观看网站| 67194国产精品免费观看| 女人被男人桶得好爽免费视频| 免费观看国产精品| 亚洲精品国产成人片| 亚洲白色白色在线播放| 亚洲av永久无码精品秋霞电影秋| 又粗又长又爽又长黄免费视频| 免费在线中文日本| 人妻视频一区二区三区免费| 免费欧洲毛片A级视频无风险| 亚洲码国产精品高潮在线| 亚洲白嫩在线观看| 理论秋霞在线看免费| 久久国产精品免费专区| 在线免费观看视频你懂的| 伊人久久亚洲综合| 亚洲伊人久久精品| 国产精品玖玖美女张开腿让男人桶爽免费看| 国产精品免费福利久久| 日本无吗免费一二区| 亚洲AV无码AV男人的天堂| 亚洲精品无播放器在线播放| 国产成人无码区免费内射一片色欲 | 亚洲欧美第一成人网站7777| 国产精品偷伦视频免费观看了| 亚洲电影在线免费观看| 亚洲精品动漫人成3d在线| ass亚洲**毛茸茸pics| 国产精品美女久久久免费| 最近中文字幕无吗高清免费视频| 亚洲国产另类久久久精品小说| 亚洲色精品VR一区区三区|