2012-11-27 54 views
1

運行每個線程時爲什麼即使在前一個線程已經調用countdown.countDown()並將Latch Count減少1之後,爲什麼countdown.getCount()始終會打印'3'?Java - COUNTDOWNLATCH中的計數

我有點厭倦了Java如何知道Latch Count已經達到0,以便它可以釋放所有3個線程。

import java.util.concurrent.CountDownLatch; 

class b { 
static final CountDownLatch countdown = new CountDownLatch(3); 

public static void main(String[] args) { 

    for (int i = 0; i < 3; ++i) { 
     Thread t = new Thread() { 
      public void run() { 
       System.out.printf("Starting on %d other threads.\n", 
         countdown.getCount()); 
       countdown.countDown(); 
       System.out.printf("new on %d other threads.\n", 
         countdown.getCount()); 
       try { 
        countdown.await(); // waits until everyone reaches this 
             // point 
        // System.out.println("Go again : " 
        // +countdown.getCount()); 
       } catch (Exception e) { 
       } 
      } 
     }; 
     t.start(); 

    } 
    System.out.println("Go"); 
} 

}

+0

上一個線程已經調用countdown.countDown()之後,邏輯錯誤出現在*中*:它可能沒有 – assylias

+2

http://ideone.com/EloGi9 - 在那裏工作正常。如果你幸運,它的行爲就像你期望的那樣。這就是未定義的多線程行爲的美妙之處 – zapl

回答

2

你開始並行3個線程。取決於他們開始的速度,他們可以在任何線程管理呼叫countDown()(至少對於「Starting on ...」行)之前打印「3」。但是,「new on ...」行應打印出2到0之間的某些範圍的數字。

+0

好吧,如果它全部開始,那麼Java如何知道(更新鎖存計數)線程可以等待釋放? – user547453

+0

@ user547453 - 我很困惑你的問題。當latch達到0時,'await()'調用返回,一旦所有的線程都調用了'countDown()',就會立即返回。 – jtahlborn

0

當線程並行運行時,所有三個線程都會打印「Starting on 3 ..」並且在線程執行countDown()之前計數不會改變。要真正瞭解發生了什麼事情,我建議您在打印報表之前預先考慮System.nanoTime()和線程名稱如下:

... 
Thread t = new Thread("Thread-" + i) { 
... 
System.out.printf("%d> %s: Starting on %d other threads.\n", System.nanoTime(), getName(), countdown.getCount()); 
countdown.countDown(); 
System.out.printf("%d> %s: new on %d other threads.\n", System.nanoTime(), getName(), countdown.getCount()); 

有時你會得到一個輸出像下面這可能給你的印象是主題-2忽視線程1的號召,倒計時:

00> Thread-0: Starting on 3 other threads. 
1407489646569324000> Thread-1: Starting on 3 other threads. 
1407489646602463000> Thread-1: new on 1 other threads. 
1407489646569513000> Thread-2: Starting on 3 other threads. 
1407489646602107000> Thread-0: new on 2 other threads. 
1407489646603275000> Thread-2: new on 0 other threads. 

然而,情況並非如此,我們可以通過查看時間戳驗證操作的正確順序。輸出中的混合是由於線程調度的固有不可預測性,這取決於哪個線程獲得了cpu拼接。

話雖如此,他們可能並不總是打印3,這取決於線程調度或延遲。作爲一個例子,嘗試把Thread.sleep(..)如下所示:

public static void main(String[] args) throws Exception { 
    for (int i = 0; i < 3; ++i) { 
     Thread t = new Thread() { 
      public void run() { 
       /* As before */ 
      } 
     }; 
     t.start(); 
     Thread.sleep(100); // Artificial Delay 
    } 
} 

現在你應該看到不同的結果,如下所示:!

1407490223575404000> Thread-0: Starting on 3 other threads. 
1407490223607879000> Thread-0: new on 2 other threads. 
1407490223676233000> Thread-1: Starting on 2 other threads. 
1407490223676818000> Thread-1: new on 1 other threads. 
1407490223777623000> Thread-2: Starting on 1 other threads. 
1407490223778221000> Thread-2: new on 0 other threads. 

在內部,CountDownLatch保持在一個先入先出隊列等待(見。的AbstractQueuedSynchronizer)。計數值是同步的,等待線程只在計數變爲0或其他線程中斷等待線程時才被釋放。這是閂鎖用來跟蹤所有線程何時到達閂鎖的機制。

如果您有興趣瞭解測試環境中的鎖存器,請參閱http://razshahriar.com/2014/08/testing-asynchronous-code-in-java-with-countdownlatch/ 希望這有助於澄清您對本程序行爲的調查。