Java並發工具類 - CountDownLatch
Java並發工具類 - CountDownLatch
1、簡介
CountDownLatch是Java1.5之後引入的Java並發工具類,放在java.util.concurrent包下面 http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html 官方API。
CountDownLatch能夠使一個或多個線程等待其他線程完成各自的工作後再執行;CountDownLatch是JDK 5+裏面閉鎖的一個實現。
閉鎖(Latch):一種同步方法,可以延遲線程的進度直到線程到達某個終點狀態。通俗的講就是,一個閉鎖相當於一扇大門,在大門打開之前所有線程都被阻斷,一旦大門打開所有線程都將通過,但是一旦大門打開,所有線程都通過了,那麽這個閉鎖的狀態就失效了,門的狀態也就不能變了,只能是打開狀態。也就是說閉鎖的狀態是一次性的,它確保在閉鎖打開之前所有特定的活動都需要在閉鎖打開之後才能完成。
與CountDownLatch第一次交互是主線程等待其它的線程,主線程必須在啟動其它線程後立即調用await方法,這樣主線程的操作就會在這個方法上阻塞,直到其他線程完成各自的任務。
其他的N個線程必須引用閉鎖對象,因為他們需要通知CountDownLatch對象,他們已經完成了各自的任務,這種機制就是通過countDown()方法來完成的。每調用一次這個方法,在構造函數中初始化的count值就減1,所以當N個線程都調用了這個方法count的值等於0,然後主線程就能通過await方法,恢復自己的任務。
這裏的主線程是相對的概念,需要根據CountDownLatch創建的場景分析。
2、主要方法
特有方法:
public CountDownLatch(int count); //指定計數的次數,只能被設置1次
public void countDown(); //調用此方法則計數減1
public void await() throws InterruptedException //調用此方法會一直阻塞當前線程,直到計時器的值為0,除非線程被中斷。
Public Long getCount(); //得到當前的計數
Public boolean await(long timeout, TimeUnit unit) //調用此方法會一直阻塞當前線程,直到計時器的值為0,除非線程被中斷或者計數器超時,返回false代表計數器超時。
From Object Inherited:
Clone、equals、hashCode、notify、notifyALL、wait等。
3、使用場景
(1)開啟多個線程分塊下載一個大文件,每個線程只下載固定的一截,最後由另外一個線程來拼接所有的分段。
(2)應用程序的主線程希望在負責啟動框架服務的線程已經啟動所有的框架服務之後再執行。
(3)確保一個計算不會執行,直到所需要的資源被初始化。
......
4、參考例子
(1)轉自:http://www.iteye.com/topic/1002652
public class CountDownLatchDemo { final static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static void main(String[] args) throws InterruptedException { CountDownLatch latch=new CountDownLatch(2);//兩個工人的協作 Worker worker1=new Worker("zhang san", 5000, latch); Worker worker2=new Worker("li si", 8000, latch); worker1.start();// worker2.start();// latch.await();//等待所有工人完成工作 System.out.println("all work done at "+sdf.format(new Date())); } static class Worker extends Thread{ String workerName; int workTime; CountDownLatch latch; public Worker(String workerName ,int workTime ,CountDownLatch latch){ this.workerName=workerName; this.workTime=workTime; this.latch=latch; } public void run(){ System.out.println("Worker "+workerName+" do work begin at "+sdf.format(new Date())); doWork();//工作了 System.out.println("Worker "+workerName+" do work complete at "+sdf.format(new Date())); latch.countDown();//工人完成工作,計數器減一 } private void doWork(){ try { Thread.sleep(workTime); } catch (InterruptedException e) { e.printStackTrace(); } } } }View Code
(2)官網例子(推薦的實現模型1):http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html
class Driver { // ... void main() throws InterruptedException { CountDownLatch startSignal = new CountDownLatch(1); CountDownLatch doneSignal = new CountDownLatch(N); for (int i = 0; i < N; ++i) // create and start threads new Thread(new Worker(startSignal, doneSignal)).start(); doSomethingElse(); // don‘t let run yet startSignal.countDown(); // let all threads proceed doSomethingElse(); doneSignal.await(); // wait for all to finish } } class Worker implements Runnable { private final CountDownLatch startSignal; private final CountDownLatch doneSignal; Worker(CountDownLatch startSignal, CountDownLatch doneSignal) { this.startSignal = startSignal; this.doneSignal = doneSignal; } public void run() { try { startSignal.await(); doWork(); doneSignal.countDown(); } catch (InterruptedException ex) {} // return; } void doWork() { ... } }View Code
(3)官網例子(推薦的實現模型2):http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html
註:
1. latch.countDown(); 建議放到finally語句裏。
2. 對這個計數器的操作都是原子操作,同時只能有一個線程去操作這個計數器。
5、常見面試題
通過上述的介紹很容易解決下面的面試題:
(1)解釋一下CountDownLatch概念?
(2)CountDownLatch 和CyclicBarrier的不同之處?
(3)給出一些CountDownLatch使用的例子?
(4) CountDownLatch 類中主要的方法?
6、參考資料
什麽時候使用CountDownLatch:http://www.importnew.com/15731.html
官網API:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html
例子:http://www.iteye.com/topic/1002652
Java並發工具類 - CountDownLatch