同步工具類 java.util.concurrent.CountDownLatch

fd5f 9年前發布 | 15K 次閱讀 Java開發 CountDownLatch

閉鎖是一種同步工具類,可以延遲線程的進度直到閉鎖到達終止狀態閉鎖的作用相當于一扇門,在閉鎖到達結束狀態之前,這扇門一直是關閉的,任何線程都不能通過這扇門,當閉鎖到達結束狀態時,這扇門會打開并允許所有線程通過當閉鎖到達結束狀態后,將不會再改變狀態,這扇門將永遠保持打開狀態 java.util.concurrent.CountDownLatch即是一個閉鎖實現,其內部包含一個計數器,該計數器被初始化為一個整數,表示需要等待事件的數量 countDown方法遞減計數器計數,如果計數到達0,則釋放所有等待中的線程 await方法使當前線程在計數器倒計數至0之前一直等待,除非等...

1、類介紹</span> </h3>

java.util.concurrent.CountDownLatch

一個同步輔助類,在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待。

用給定的計數 初始化 CountDownLatch。由于調用了 countDown() 方法,所以在當前計數到達零之前,await 方法會一直受阻塞。之后,會釋放所有等待的線程,await 的所有后續調用都將立即返回。這種現象只出現一次——計數無法被重置。如果需要重置計數,請考慮使用 CyclicBarrier。

2、使用場景

在一些應用場合中,需要等待某個條件達到要求后才能做后面的事情;同時當線程都完成后也會觸發事件,以便進行后面的操作。 這個時候就可以使用CountDownLatch。CountDownLatch最重要的方法是countDown()和await(),前者主要是倒數一次,后者是等待倒數到0,如果沒有到達0,就只有阻塞等待了。

3、方法說明

countDown

public void countDown()
遞減鎖存器的計數,如果計數到達零,則釋放所有等待的線程。如果當前計數大于零,則將計數減少。如果新的計數為零,出于線程調度目的,將重新啟用所有的等待線程。


如果當前計數等于零,則不發生任何操作。

</div>

await

public boolean await(long timeout, TimeUnit unit)
              throws InterruptedException
使當前線程在鎖存器倒計數至零之前一直等待,除非線程被 中斷或超出了指定的等待時間。如果當前計數為零,則此方法立刻返回true值。


如果當前計數大于零,則出于線程調度目的,將禁用當前線程,且在發生以下三種情況之一前,該線程將一直處于休眠狀態:

  • 由于調用 countDown() 方法,計數到達零;或者
  • 其他某個線程中斷當前線程;或者
  • 已超出指定的等待時間。
  • </ul>

    如果計數到達零,則該方法返回true值。

    如果當前線程:

    • 在進入此方法時已經設置了該線程的中斷狀態;或者
    • 在等待時被中斷
    • </ul>

      則拋出 InterruptedException,并且清除當前線程的已中斷狀態。如果超出了指定的等待時間,則返回值為false。如果該時間小于等于零,則此方法根本不會等待。

      參數:timeout- 要等待的最長時間unit-timeout參數的時間單位。

      返回:如果計數到達零,則返回true;如果在計數到達零之前超過了等待時間,則返回false

      拋出:InterruptedException- 如果當前線程在等待時被中斷

      4、使用實例

      // 一個CountDouwnLatch實例是不能重復使用的,也就是說它是一次性的,鎖一經被打開就不能再關閉使用了,如果想重復使用,請考慮使用CyclicBarrier。
      public class CountDownLatchTest {

      // 模擬了100米賽跑,10名選手已經準備就緒,只等裁判一聲令下。當所有人都到達終點時,比賽結束。
      public static void main(String[] args) throws InterruptedException {
      
          // 開始的倒數鎖
          final CountDownLatch begin = new CountDownLatch(1); 
      
          // 結束的倒數鎖
          final CountDownLatch end = new CountDownLatch(10); 
      
          // 十名選手
          final ExecutorService exec = Executors.newFixedThreadPool(10); 
      
          for (int index = 0; index < 10; index++) {
              final int NO = index + 1; 
              Runnable run = new Runnable() {
                  public void run() { 
                      try { 
                          // 如果當前計數為零,則此方法立即返回。
                          // 等待
                          begin.await(); 
                          Thread.sleep((long) (Math.random() * 10000)); 
                          System.out.println("No." + NO + " arrived"); 
                      } catch (InterruptedException e) { 
                      } finally { 
                          // 每個選手到達終點時,end就減一
                          end.countDown();
                      } 
                  } 
              }; 
              exec.submit(run);
          } 
          System.out.println("Game Start"); 
          // begin減一,開始游戲
          begin.countDown(); 
          // 等待end變為0,即所有選手到達終點
          end.await(); 
          System.out.println("Game Over"); 
          exec.shutdown(); 
      }
      

      }</pre>

      </span>

 本文由用戶 fd5f 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!