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

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

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

    關注技術,關注生活

    任何事情只要開始去做,永遠不會太遲。
    posts - 5, comments - 23, trackbacks - 0, articles - 18
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    [轉]Java 線程應該注意的問題

    Posted on 2006-12-09 13:45 errorfun 閱讀(207) 評論(0)  編輯  收藏 所屬分類: JAVA
    1.同步對象的恒定性All java objects are references.

      對于局部變量和參數來說,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接口的方法。本文推薦這種方法。

      首先,把需要共享的數據放在一個實現Runnable接口的類里面,然后,把這個類的實例傳給多個Thread的構造方法。這樣,新創建的多個Thread,都共同擁有一個Runnable實例,共享同一份數據。

      如果采用繼承Thread類的方法,就只好使用static靜態成員了。如果共享的數據比較多,就需要大量的static靜態成員,令程序數據結構混亂,難以擴展。這種情況應該盡量避免。

      編寫一段多線程代碼,處理一個稍微復雜點的問題。兩種方法的優劣,一試便知。

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

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

      線程之間的通知,通過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();?  }
    ?  }
    ?


       5.跨類的同步對象對于簡單的問題,可以把訪問共享資源的同步代碼都放在一個類里面。

      但是對于復雜的問題,我們需要把問題分為幾個部分來處理,需要幾個不同的類來處理問題。這時,就需要在不同的類中,共享同步對象。比如,在生產者和消費者之間共享同步對象,在讀者和寫者之間共享同步對象。

      如何在不同的類中,共享同步對象。有幾種方法實現,

     ?。?)前面講過的方法,使用static靜態成員,(或者使用Singleton Pattern.)

      (2)用參數傳遞的方法,把同步對象傳遞給不同的類。

     ?。?)利用字符串常量的“原子性”。

      對于第三種方法,這里做一下解釋。一般來說,程序代碼中的字符串常量經過編譯之后,都具有唯一性,即,內存中不會存在兩份相同的字符串常量。

     ?。ㄍǔG闆r下,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)用參數傳遞的方法,把同步對象傳遞給不同的類。

    主站蜘蛛池模板: 波多野结衣一区二区免费视频| 欧美大尺寸SUV免费| 亚洲成年人啊啊aa在线观看| 亚洲国产综合AV在线观看| 无码人妻一区二区三区免费手机 | 亚洲精品二三区伊人久久| 97在线视频免费公开观看| 久久亚洲AV成人无码国产| 13一14周岁毛片免费| 亚洲av专区无码观看精品天堂| 成年人性生活免费视频| 日日摸日日碰夜夜爽亚洲| 亚洲欧洲精品成人久久曰影片| 人成免费在线视频| 无码中文字幕av免费放| 亚洲不卡影院午夜在线观看| 小日子的在线观看免费| 亚洲精品一级无码鲁丝片 | 免费萌白酱国产一区二区三区| 亚洲精品无码永久中文字幕| 久久免费线看线看| 亚洲H在线播放在线观看H| 日韩免费一区二区三区| 亚洲影视一区二区| 日本一道一区二区免费看| 手机永久免费的AV在线电影网| 精品亚洲一区二区| 久久午夜免费视频| 91天堂素人精品系列全集亚洲| 国产成人精品久久免费动漫| 亚洲国产精品婷婷久久| 国产曰批免费视频播放免费s| 亚洲αv久久久噜噜噜噜噜| 久99久无码精品视频免费播放| 亚洲AV乱码久久精品蜜桃| 国产在线观看片a免费观看| 偷自拍亚洲视频在线观看99| 国产AV无码专区亚洲AWWW| 精精国产www视频在线观看免费| 亚洲视频.com| 亚洲国产精品毛片av不卡在线 |