闭锁与栅栏
在介绍闭锁和栅栏之前,我们先来看下这个实例:
我们用三个线程实现男女朋友去看电影的示例,正常情况是需要男女双方都到达后才能一起去看电影,我们看下这段代码:
public class DownLatch {
private static CountDownLatch countDownLatch = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
downLatch.girlArriveMovie();
}).start();
new Thread(()-> {
downLatch.boyArriveMovie();
}).start();
downLatch.startWatchMovie();
}
public void girlArriveMovie(){
System.out.println("女孩到达电影院");
}
public void boyArriveMovie(){
System.out.println("男生到达电影院");
}
public void startWatchMovie(){
System.out.println("男女生都到达电影院,开始看电影");
}
}
可能结果之一:
女孩到达电影院
男女生都到达电影院,开始看电影
男生到达电影院
可能结果之二:
女孩到达电影院
男生到达电影院
男女生都到达电影院,开始看电影
这和我们理想的情况不一样,来看看如何使用闭锁以及栅栏达到我们想要的理想结果。
闭锁
闭锁是一种同步工具。类似于一扇门:在使用闭锁的所有线程到达结束状态之前,这扇门一直是关闭着的。不允许任何线程通过,当到达结束状态时这扇门就会打开并允许所有闭锁相关的线程通过,且当打开了,就永远保持打开状态。
作用:可以用来确保某些任务等到其他任务完成之后才开始执行。
public class DownLatch {
private static CountDownLatch countDownLatch = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
DownLatch downLatch = new DownLatch();
new Thread(() -> {
downLatch.girlArriveMovie();
countDownLatch.countDown();
}).start();
new Thread(()-> {
downLatch.boyArriveMovie();
countDownLatch.countDown();
}).start();
countDownLatch.await();
downLatch.startWatchMovie();
}
public void girlArriveMovie(){
System.out.println("女孩到达电影院");
}
public void boyArriveMovie(){
System.out.println("男生到达电影院");
}
public void startWatchMovie(){
System.out.println("男女生都到达电影院,开始看电影");
}
}
女孩到达电影院
男生到达电影院
男女生都到达电影院,开始看电影
来看下如何使用闭锁达到我们想要的效果的。
new CountDownLatch(2);
//设置计数器为2
countDownLatch.countDown();
// 计数器减一
countDownLatch.await();
//是否计数器未0,如果是等待其他线程执行完毕
//后在执行main线程里的downLatch.startWatchMovie();
//方法
栅栏
栅栏和闭锁可以达到相同的效果,但是不同的是栅栏是等待所有的栅栏工作线程中都到达某一步,所有的栅栏工作线程才会继续执行。
public class CyclicBarrierExample {
public final static CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
public static void main(String[] args) {
CyclicBarrierExample cyclicBarrierExample = new CyclicBarrierExample();
ExecutorService threadPool = Executors.newFixedThreadPool(2);
threadPool.execute(() -> cyclicBarrierExample.girlArriveMovie());
threadPool.execute(() -> cyclicBarrierExample.boyArriveMovie());
threadPool.shutdown();
}
public void girlArriveMovie(){
System.out.println("女孩到达电影院");
try {
Thread.sleep(500);
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
startWatchMovie();
}
public void boyArriveMovie(){
System.out.println("男生到达电影院");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
startWatchMovie();
}
public void startWatchMovie(){
System.out.println("男女生都到达电影院,开始看电影");
}
}
输出结果:
女孩到达电影院
男生到达电影院
男女生都到达电影院,开始看电影
男女生都到达电影院,开始看电影
Thread.sleep(500);
// 执行到这里睡眠500ms
cyclicBarrier.await();
//等待其他的栅栏工作线程
//执行到这里
//才会继续往下执行