在上一篇博客中,我們用Callable實現了這個功能:用Callable實現在走完10個線程之後再進行操作,其中也提到了使用CountDownLatch實現是一個更好地選擇,下面,我們就來看看如何使用用CountDownLatch實現在走完10個線程之後再進行操作。 我們先來看看《JAVA編程思想第四版》中對CountDownLatch的描述:
CountDownLatch被用來同步一個或多個任務,強制它們等待由其他任務執行的一組操作完成。
你可以向CcountDownLatch對象設置一個初始計數值,任何在這個對象上調用wait的方法都將阻塞,直至這個計數值到達0。
其他任務在結束其工作時,可以再該對象上調用countDown()來減小這個計數值。CountDownLatch被設計爲只觸發一次,計數值
不能被重置。如果你需要能夠重置計數值的版本,則可以使用CyclicBarrier。
調用countDown()的任務在產生這個調用時並沒有被阻塞只有對await()的調用會被阻塞,直到計數值到達0.
CountDownLatch的典型用法是將一個程序分爲n個互相獨立的可解決的任務,並創建值爲0的CountDownLatch。(此處
應該是創建值爲n的CountDownLatch)當每個任務完成時,都會在這個鎖存器上調用countDown()。等待問題唄解決的
任務在這個鎖存器上調用await(),將他們自己攔住,直到鎖存器上技術結束。
再來看看具體要求的具體應用:
/**
* 2018-05-05
* @author liujie
*
*/
public class TestCountDownLatch {
public static void main(String[] args) throws Exception{
int SIZE = 10;
CountDownLatch latch = new CountDownLatch(SIZE);
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
List<Runnable> threads = new ArrayList<Runnable>();
for (int i = 0; i < SIZE; i++) {
//多個任務線程共享一個CountDownLatch實例
threads.add(new MyThread(latch));
}
for (Runnable runnable : threads) {
Thread.sleep(50);
cachedThreadPool.execute(runnable);
}
System.out.println("main Thread finished starting threads--"
+ new Date().getSeconds());
//主線程會在這裏等待,直到latch計數值到達0
latch.await();
//當latch計數值到達0,說明任務線程都完成了各自任務,主線程繼續往下
System.out.println("main Thread go on working--" + new Date().getSeconds());
}
}
class MyThread implements Runnable{
private CountDownLatch latch;
private static transient int count = 0;
private static Random random = new Random();
private int id = count ++;
public MyThread(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
int workTimeSeconds = random.nextInt(10) + 1;
System.out.println("Thread-" + id + "\tstart running for "
+ workTimeSeconds + " seconds--" + new Date().getSeconds());
try {
Thread.sleep(1000 * workTimeSeconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
//在完成自己的任務後,將latch的計數值減一
latch.countDown();
}
}
以下是控制檯的打印:
Thread-2 start running for 8 seconds--41
Thread-1 start running for 2 seconds--41
Thread-3 start running for 3 seconds--41
Thread-0 start running for 5 seconds--41
Thread-4 start running for 2 seconds--41
Thread-5 start running for 6 seconds--41
Thread-6 start running for 4 seconds--42
Thread-7 start running for 9 seconds--42
Thread-8 start running for 4 seconds--42
main Thread finished starting threads--42
Thread-9 start running for 1 seconds--42
main Thread go on working--51
由運行結果可知,程序實現了完成了題目的要求,主線程在第51秒的時候繼續下面的任務,這是因爲任務線程7是最後一個完成的任務(第42秒開始,耗時9秒,在51秒時完成).
我對CountDownLatch的理解:
就相當於一個組長,在接到一個任務以後,將任務分爲N份,並在一個任務計數器開啓N個亮燈進行記錄(new CountDownLath(N)),然後將這N份任務交給N個組員去完成(threadPool開啓N個線程)。每個組員在接到任務後就各自忙自己的,在完成了他們的任務以後,就在任務計數器上熄滅一個燈(latch.countDown()),提示已經完成了自己的任務。有需要的人就會對這個任務計數器進行監控(latch.await()),直到所有的等都熄滅了,纔會繼續工作。