CountDownLatch
一個線程需要等到其他線程進行某操作時,可以使用CountDownLatch。 CountDownLatch構造方法,帶有一個int類型的參數。
public CountDownLatch(int count)
當一個線程調用countDownLatch.await()時,線程會等待。直到其他線程執行 countDownLatch.countDown()。每執行一個countDown方法,初始化的count會減一,直到count=0時,等待線程才被喚醒。
假設場景顧客餐廳吃飯,需要等待做飯,炒菜,上湯都完成了,纔開始吃飯。 代碼:
//顧客線程
public class Customer implements Runnable {
private final CountDownLatch countDownLatch;
public Customer(CountDownLatch countDownLatch){
this.countDownLatch=countDownLatch;
}
public void run() {
System.out.println("點完菜,等待開吃");
try {
this.countDownLatch.await();
System.out.println("開飯了。。。。。。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(3);
Thread customer = new Thread(new Customer(countDownLatch));
//顧客進餐廳點菜
customer.start();
new Thread(){
@Override
public void run() {
try {
System.out.println("做飯");
}finally {
countDownLatch.countDown();
}
}
}.start();
new Thread(){
@Override
public void run() {
try {
System.out.println("炒菜");
}finally {
countDownLatch.countDown();
}
}
}.start();
new Thread(){
@Override
public void run() {
try {
System.out.println("上湯");
}finally {
countDownLatch.countDown();
}
}
}.start();
customer.join();
}
輸出:
點完菜,等待開吃
做飯
炒菜
上湯
開飯了。。。。。。。。
結果正確,等待做飯,炒菜,上湯都完成了,纔開始吃飯。
總結:
- countDownLatch內部通過共享鎖實現
- countDown方法最好放在finally代碼塊中執行,防止線程永遠等待
- CountDownLatch再 count減到0之後,再次執行countDown不會有影響,count不變。
- await方法有重載方法
public boolean await(long timeout, TimeUnit unit)
,等待一段時間後恢復。 - countDownLatch只能使用一次,count=0時,不能回滾再次使用。