2013-07-31 93 views
0

爲什麼通常線程樣本將很多代碼放在同步塊中。根據我在以下情況下同步的理解是隻用於鎖定b。對於等待和通知:瞭解在java中同步

主要類的ThreadA:

class ThreadA { 
     public static void main(String [] args) { 
     ThreadB b = new ThreadB(); 
     b.start(); 

     synchronized(b) { 
      try { 
       System.out.println("Waiting for b to complete..."); 

       b.wait(); 
      } catch (InterruptedException e) {} 
      System.out.println("Total is: " + b.total); 
      System.out.println(Thread.currentThread().getName()); 

     } 
    } 
    } 

和類ThreadB:

class ThreadB extends Thread { 
    int total;  
    public void run() { 
     synchronized(this) 
     { 
      System.out.println(); 
      for(int i=0;i<100;i++) 
      { 
       System.out.println(Thread.currentThread().getName()); 
       total += i; 
      } 
      notify(); 
     } 
    } 
    } 

會有什麼改變,如果我把waitnotify寫入​​區塊:

class ThreadA { 
     public static void main(String [] args) { 
     ThreadB b = new ThreadB(); 
     b.start(); 
      try { 
       System.out.println("Waiting for b to complete..."); 

       synchronized(b) { b.wait();} 
      } catch (InterruptedException e) {} 
      System.out.println("Total is: " + b.total); 
      System.out.println(Thread.currentThread().getName()); 


    } 
    } 

回答

0

請注意total += i而不是 Java中的原子操作。所以你必須同步這個構造。

您還沒有同步notify()和wait(),因爲它們的鎖在內部處理。

+0

但在這種特殊情況下,不同步總計+ = i是安全的,因爲沒有人會編輯它,並且根據代碼,只有在通知後纔會讀取,而不會編輯總數。我錯了? – vico

+0

你的意思是我可以寫'b.wait();'而不是'synchronized(b){b.wait();}'? – vico

4

根據我在下面的情況下同步的理解是隻用於鎖定b。對於等待和通知

你的理解是錯誤的。

​​還用於:

  • 互斥,以確保只有一個線程執行的代碼同時
  • 通過特定監視器「把守」確保跨線程內存訪問是正確的(即一個線程看到)被另一個線程所做的更改

如果我把只是等待和通知同步塊什麼將改變:

在這種特殊情況下,它會有所作爲基礎上的競爭條件 - 在原來的代碼,如果新thread開始在原來的線程達到同步塊之前執行,它不會得到至於「等待b完成」,直到第二個線程結束......在這一點上它將在wait中永遠阻塞。

請注意,這是一個非常糟糕的主意伺候Thread顯示器,如wait/notifyThread內部使用。

總之,您使用的示例以各種方式開始很糟糕 - 但同步用於多於wait/notify

+0

>請注意,等待線程監視器是一個非常糟糕的主意。但是當我需要等待線程完成工作時,如何處理這種特殊情況? – vico

+0

@ user1501700:使用不同的監視器而不是'Thread' ...或者更好的方法,使用'Thread.join()'作爲它的用途。就個人而言,我不會擴展'Thread' - 實現'Runnable'並將實例傳遞給'Thread'構造函數。 –