併發工具類系列:java
Java併發工具類(閉鎖CountDownLatch)bash
Java併發工具類(柵欄CyclicBarrier)markdown
閉鎖是一種同步工具類,能夠延遲線程的進度直到其到達終止狀態。dom
CountDownLatch是一種靈活的閉鎖實現,它能夠使一個或者多個線程等待一組事件的發生。ide
閉鎖狀態包含一個計數器,該計數器被初始化爲一個正數,表示須要等待的事件數量。countDown方法遞減計數器,表示已經有一個事件已經發生了。而await方法等待計數器達到0,這表示全部須要等待的事件都已經發生。若是計數器的值非0,那麼await會一直阻塞直到計數器爲0,或者等待中的線程中斷或者超時。 下面,咱們以經典的運動員賽跑舉例: 工具
n
個,槍響只須要一聲,等待的這一聲槍響到了,開始門也就打開了,全部運動員開始跑。n
個運動員,直到n爲0。下面咱們根據具體的代碼來演示CountDownLatch的用法:post
package concurrency; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; class Runner implements Runnable { private static int counter = 0; private final int id = counter++; private static Random rand= new Random(47); private final CountDownLatch start_latch; private final CountDownLatch end_latch; public Runner(CountDownLatch start_latch, CountDownLatch end_latch) { this.start_latch = start_latch; this.end_latch = end_latch; } @Override public void run() { try { start_latch.await(); //全部運動員都在準備狀態中,等待教練釋放開始門 try { doWork(); //每一個人跑步的時間不一樣 end_latch.countDow n(); //跑完後,告訴教練跑完了 } catch (InterruptedException e) { System.out.println("Interrupted Runner" + id); } } catch (InterruptedException e) { System.out.println("Interrupted Runner" + id); } } public void doWork() throws InterruptedException { TimeUnit.MILLISECONDS.sleep(rand.nextInt(2000)); System.out.println(this + "completed"); } @Override public String toString() { return String.format("%1$-3d", id); } } class Coach implements Runnable { private final CountDownLatch start_latch; private final CountDownLatch end_latch; public Coach(CountDownLatch start_latch, CountDownLatch end_latch) { this.start_latch = start_latch; this.end_latch = end_latch; } @Override public void run() { start_latch.countDown(); //教練釋放了開始門,運動員們都開始跑 System.out.println("Coach say: Ready!!!! Go!!!!"); try { end_latch.await(); //當結束門的count down減爲0時,教練宣佈全部人都跑完了。 System.out.println("All runner passed the end point"); } catch (InterruptedException ex) { System.out.println(this + " interrupted"); } } } public class TestRunner { private static final int SIZE = 10; public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); CountDownLatch startGate = new CountDownLatch(1); CountDownLatch endGate = new CountDownLatch(SIZE); for (int i = 0; i < SIZE; i++) { exec.execute(new Runner(startGate, endGate)); } exec.execute(new Coach(startGate, endGate)); exec.shutdown(); } } 複製代碼
CountDownLatch強調的是一個線程(或多個)須要等待另外的n個線程幹完某件事情以後才能繼續執行。 上述例子,Coach線程是裁判,10個Runner是跑步的。運動員先準備,裁判喊跑,運動員纔開始跑(這是第一次同步,對應startGate)。10我的誰跑到終點了,countdown一下,直到10我的所有到達,裁判喊停(這是第二次同步,對應endGate)。 最後運行結果以下:this
Coach say: Ready!!!! Go!!!! 7 completed 9 completed 5 completed 8 completed 2 completed 0 completed 6 completed 4 completed 1 completed 3 completed All runner passed the end pointspa