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

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

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

    Thread中同步和共享數據應該注意的地方

    1.同步對象的恒定性
             對于局部變量和參數來說,java里面的int, float, double, boolean等基本數據類型,都在棧上。這些基本類型是無法同步的;java里面的對象(根對象是Object),全都在堆里,指向對象的reference在棧上。

             java中的同步對象,實際上是對于reference所指的“對象地址”進行同步。
            需要注意的問題是,千萬不要對同步對象重新賦值。舉個例子。
                class A implements Runnable{
                    Object lock = new Object();

                        void run(){
                            for(...){
                                synchronized(lock){
                                    // do something
                                        ...
                                      lock = new Object();
                                 }
                            }
                        }
                }

            run函數里面的這段同步代碼實際上是毫無意義的。因為每一次lock都給重新分配了新的對象的reference,每個線程都在新的reference同步。大家可能覺得奇怪,怎么會舉這么一個例子。因為我見過這樣的代碼,同步對象在其它的函數里被重新賦了新值。這種問題很難查出來。所以,一般應該把同步對象聲明為final。 final Object lock = new Object();

    使用Singleton Pattern 設計模式來獲取同步對象,也是一種很好的選擇。


    2.如何放置共享數據,粒度,跨類的同步對象
            

            實現線程,有兩種方法,一種是繼承Thread類,一種是實現Runnable接口。
            首先,把需要共享的數據放在一個實現Runnable接口的類里面,然后,把這個類的實例傳給多個Thread的構造方法。這樣,新創建的多個Thread,都共同擁有一個Runnable實例,共享同一份數據。如果采用繼承Thread類的方法,就只好使用static靜態成員了。如果共享的數據比較多,就需要大量的static靜態成員,令程序數據結構混亂,難以擴展。這種情況應該盡量避免。編寫一段多線程代碼,處理一個稍微復雜點的問題。兩種方法的優劣,一試便知。

            線程同步的粒度越小越好,即,線程同步的代碼塊越小越好。盡量避免用synchronized修飾符來聲明方法。盡量使用synchronized(anObject)的方式,如果不想引入新的同步對象,使用synchronized(this)的方式。而且,synchronized代碼塊越小越好。

            對于簡單的問題,可以把訪問共享資源的同步代碼都放在一個類里面。
            但是對于復雜的問題,我們需要把問題分為幾個部分來處理,需要幾個不同的類來處理問題。這時,就需要在不同的類中,共享同步對象。比如,在生產者和消費者之間共享同步對象,在讀者和寫者之間共享同步對象。
    如何在不同的類中,共享同步對象。有幾種方法實現,
    (1)前面講過的方法,使用static靜態成員,(或者使用Singleton Pattern.)
    (2)用參數傳遞的方法,把同步對象傳遞給不同的類。
    (3)利用字符串常量的“原子性”。
    對于第三種方法,這里做一下解釋。一般來說,程序代碼中的字符串常量經過編譯之后,都具有唯一性,即,內存中不會存在兩份相同的字符串常量。
    (通常情況下,C++,C語言程序編譯之后,也具有同樣的特性。)

        比如,我們有如下代碼。
            String A = “atom”;
            String B = “atom”;

        我們有理由認為,A和B指向同一個字符串常量。即,A==B。注意,聲明字符串變量的代碼,不符合上面的規則。
            String C= new String(“atom”);
            String D = new String(“atom”);
        這里的C和D的聲明是字符串變量的聲明,所以,C != D。

    有了上述的認識,我們就可以使用字符串常量作為同步對象。比如我們在不同的類中,使用synchronized(“myLock”), “myLock”.wait(),“myLock”.notify(), 這樣的代碼,就能夠實現不同類之間的線程同步。本文并不強烈推薦這種用法,只是說明,有這樣一種方法存在。本文推薦第二種方法,(2)用參數傳遞的方法,把同步對象傳遞給不同的類。


    3.線程之間的通知

    這里使用“通知”這個詞,而不用“通信”這個詞,是為了避免詞義的擴大化。

    線程之間的通知,通過Object對象的wait()和notify() 或notifyAll() 方法實現。

    下面用一個例子,來說明其工作原理:

    假設有兩個線程,A和B。共同擁有一個同步對象,lock。

    1.首先,線程A通過synchronized(lock) 獲得lock同步對象,然后調用lock.wait()函數,放棄lock同步對象,線程A停止運行,進入等待隊列。

    2.線程B通過synchronized(lock) 獲得線程A放棄的lock同步對象,做完一定的處理,然后調用 lock.notify() 或者lock.notifyAll() 通知等待隊列里面的線程A。

    3.線程A從等待隊列里面出來,進入ready隊列,等待調度。

    4.線程B繼續處理,出了synchronized(lock)塊之后,放棄lock同步對象。

    5.線程A獲得lock同步對象,繼續運行。

     

    例子代碼如下:

    public class SharedResource implements Runnable{

    Object lock = new Object();

     

    public void run(){

    // 獲取當前線程的名稱。

    String threadName = Thread.currentThread().getName();

     

    if( “A”.equals(threadName)){

    synchronized(lock){ //線程A通過synchronized(lock) 獲得lock同步對象

    try{

    System.out.println(“ A gives up lock.”);

    lock.wait(); // 調用lock.wait()函數,放棄lock同步對象,

    // 線程A停止運行,進入等待隊列。

    }catch(InterruptedException e){

    }

     

    // 線程A重新獲得lock同步對象之后,繼續運行。

    System.out.println(“ A got lock again and continue to run.”);

    } // end of synchronized(lock)

    }

     

    if( “B”.equals(threadName)){

    synchronized(lock){//線程B通過synchronized(lock) 獲得線程A放棄的lock同步對象

    System.out.println(“B got lock.”);

     

    lock.notify(); //通知等待隊列里面的線程A,進入ready隊列,等待調度。

     

    //線程B繼續處理,出了synchronized(lock)塊之后,放棄lock同步對象。

    System.out.println(“B gives up lock.”);

    } // end of synchronized(lock)

     

    boolean hasLock = Thread.holdsLock(lock); // 檢查B是否擁有lock同步對象。

    System.out.println(“B has lock ? -- ” +hasLock); // false.

    }

    }

    }


    public class TestMain{

    public static void main(){

    Runnable resource = new SharedResource();


    Thread A = new Thread(resource,”A”);

    A.start();


    // 強迫主線程停止運行,以便線程A開始運行。

      try {

    Thread.sleep(500);

    }catch(InterruptedException e){

    }

    Thread B = new Thread(resource,”B”);

    B.start();

    }

    }




    posted on 2010-07-14 22:22 胡鵬 閱讀(920) 評論(0)  編輯  收藏


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


    網站導航:
     

    導航

    <2010年7月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    統計

    常用鏈接

    留言簿(3)

    隨筆分類

    隨筆檔案

    agile

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 91亚洲国产成人久久精品网站| 国产成人A人亚洲精品无码| 亚洲天堂中文资源| 久久成人a毛片免费观看网站| 亚洲精品美女久久777777| 国产精品午夜免费观看网站| 国产美女亚洲精品久久久综合| igao激情在线视频免费| 久久久久亚洲AV无码专区桃色| 久久WWW免费人成—看片| 久久亚洲国产精品五月天婷| 国产精品内射视频免费| 永久亚洲成a人片777777| 久久久久久久久久国产精品免费| 亚洲专区在线视频| 99无码人妻一区二区三区免费| 亚洲日韩精品国产3区| 国产jizzjizz免费视频| www.av在线免费观看| 亚洲精品国产精品乱码不卡√| 亚洲视频在线观看免费| 国产91在线|亚洲| 国产免费观看青青草原网站| 国产精品午夜免费观看网站| 亚洲第一成年人网站| 四虎在线视频免费观看| 四虎国产精品永免费| 亚洲精品网站在线观看你懂的| 女人被免费视频网站| 久青草视频在线观看免费| 亚洲春色在线观看| 国产成人免费永久播放视频平台 | 国产成人精品日本亚洲专区61| 小草在线看片免费人成视久网| 33333在线亚洲| 亚洲美女高清一区二区三区| 99re在线精品视频免费| 国产亚洲精品国产福利在线观看| 亚洲中文字幕无码久久精品1 | 亚洲偷自拍拍综合网| 国产成人免费午夜在线观看|