这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战
场景
这边模拟一个场景教室里面有6个同学+1个值日生,值日生需要等到教室里所有其他同学都离开之后完成关门的任务。然后根据需求模拟出下面的代码
public class CountDownLatchDemo {
public static void main(String[] args) {
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "号同学离开教室~~~");
}, String.valueOf(i)).start();
}
System.out.println("值日生关门走啦~~~");
}
}
运行结果:
1号同学离开教室~~~
值日生关门走啦~~~
2号同学离开教室~~~
3号同学离开教室~~~
6号同学离开教室~~~
5号同学离开教室~~~
4号同学离开教室~~~
可以看到由于多线程环境下,可能其他线程还没有执行完成(其他同学还没有离开教室),main线程就先执行了值日生关门走啦的操作,于是为了解决这个问题我们引入了java.util.concurrent包下的CountDownLatch
- CountDownLatch有一个正数计数器,countDown()方法对计数器做减操作,await()方法等待计数器达到0。所有await的线程都会阻塞直到计数器为0或者等待线程中断或者超时。
闭锁(倒计时锁)的作用
- 协调线程,让某个线程等到倒计时结束再开始执行
- 可以应用于控制线程执行的先后顺序
源码分析
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
可以看到CountDownLatch中维护了一个内部类Sync,而Sync继承自AbstractQueuedSynchronizer, 而AbstractQueuedSynchronizer中有一个变量private volatile int state;保证了state变量的可见性
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "号同学离开教室~~~");
countDownLatch.countDown();
}, String.valueOf(i)).start();
}
countDownLatch.await();
System.out.println("值日生关门走啦~~~");
}
}
运行结果:
1号同学离开教室~~~
4号同学离开教室~~~
6号同学离开教室~~~
3号同学离开教室~~~
2号同学离开教室~~~
5号同学离开教室~~~
值日生关门走啦~~~