CountDownLatch 是由java併發包提供的一個同步計數器,從字面意義上去理解可以分成兩部分CountDown 和 Latch,CountDown就是計數的意思,Latch是門閂,這個同步工具就是通過保證多線程環境下,通過門閂限制主線程執行,子線程執行後計數減1,直到減爲0,門閂打開,主線程執行。
場景一:主任務等待其它子任務完成後再執行。
背景:電影院等待所有人都到齊了還開始播放電影,有一個電影院的類爲主線程,看電影的人爲子線程,假設電影院能容納5人看電影,下面的類將利用CountDownLatch實現該功能。
public class Cinema {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(5);
ExecutorService executor = Executors.newFixedThreadPool(3);
for(int i=0; i<5; i++){
executor.execute(new Person(countDownLatch));
}
System.out.println("電影院等待人入場...");
//阻塞當前線程,直到計數器的值爲0
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("人已到齊,開始播放電影...");
}
}
public class Person implements Runnable{
private CountDownLatch countDownLatch;
public Person(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
Thread.sleep((long) (Math.random() * 0));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(String.format("%s又有觀衆入場了", Thread.currentThread().getId()));
countDownLatch.countDown();
System.out.println(String.format("%s還有%s人未入場", Thread.currentThread().getId(), countDownLatch.getCount()));
}
}
執行下看結果:
電影院等待人入場...
13又有觀衆入場了
11又有觀衆入場了
12又有觀衆入場了
11還有3人未入場
13還有4人未入場
12還有2人未入場
13又有觀衆入場了
11又有觀衆入場了
13還有1人未入場
人已到齊,開始播放電影...
11還有0人未入場
這個時候可以思考一下現實情況,不是任何時候電影院都是滿場才放電影的,那麼就需要設置一個時間,如果到時間了人還未到齊,就開始播放電影,這個程序怎麼寫呢。
public class Cinema {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(10);
ExecutorService executor = Executors.newFixedThreadPool(3);
for(int i=0; i<5; i++){
executor.execute(new Person(countDownLatch));
}
System.out.println("電影院等待人入場...");
//阻塞當前線程,直到計數器的值爲0
try {
countDownLatch.await(300, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("人已到齊,開始播放電影...");
}
}
這裏用了CountDownLatch的await的另外一個重載方法,並且增加了CountDownLatch的閾值,讓人更多一些方便跑數據。看結果:
電影院等待人入場...
12又有觀衆入場了
13又有觀衆入場了
13還有8人未入場
12還有9人未入場
11又有觀衆入場了
11還有7人未入場
12又有觀衆入場了
12還有6人未入場
13又有觀衆入場了
13還有5人未入場
人已到齊,開始播放電影...
發現還有5人未到場的時候,電影就開始播放了,是不是很贊。現在大家是不是對CountDownLatch的使用得心應手了,在這裏需要提醒的是多線程環境下一定要注意異常,如果發生了異常該如何保證數據一致性,主線程是否要做回滾處理。我們在利用多線程實現性能提升的時候,必然會有線程安全的問題。