一、CountDownLatch - 闭锁/做减法
人都走了才关门
- 使一个线程等待其他线程各自执行完毕后再执行;
- 是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。
// 参数count为计数值
CountDownLatch countDownLatch = new CountDownLatch(6);
// 调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
countDownLatch.await();
// 将count值减1
countDownLatch.countDown();
二、CyclicBarrier - 栅栏/屏障/做加法
人到齐了才开会/集齐七颗龙珠才能召唤神龙
- 字面意思是可循环使用的屏障
- 让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障才会开门,所有被屏障拦截的线程才会继续干活,当线程到达栅栏位置时将调用await方法。如果所有线程都到达栅栏位置,那么栅栏将打开,此时所有的线程都将被释放,而栅栏将被重置以便下次使用。
CyclicBarrier cyclicBarrier = new CyclicBarrier(7);
// 屏障/栅栏同步点
cyclicBarrier.await();
四、CountDownLatch和CyclicBarrier区别
- CountDownLatch是一个计数器,线程完成一个记录一个,计数器递减,只能只用一次,闭锁用于等待事件;
- CyclicBarrier的计数器更像一个阀门,需要所有线程都到达,然后继续执行,计数器递增,提供reset功能,可以多次使用,栅栏用于等待其他线程
五、Semaphore 计数信号量/信号灯
争车位,30量车争20个车位
- 计数信号量,必须由获取它的线程释放
- 常用于限制可以访问某些资源的线程数量,例如通过 Semaphore 限流。
- 有两个目的,第一个是多个共享资源互斥使用,第二个是并发线程数的控制
- 信号量为多个线程协作提供了更强大的控制方法,无论是ReentrantLock还是Synchronized一次都只允许一个线程访问一个资源。信号量允许多个线程同时访问同一个资源。
// 3个车位
Semaphore semaphore = new Semaphore(3);
// 6量车
for (int i = 0; i <= 6; i++) {
new Thread(() -> {
try {
// 获取锁资源
semaphore.acquire();
// 抢车位
System.out.println(Thread.currentThread().getName() + " 抢到车位...");
// 模拟车停靠时间
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName() + " 停车3秒后离开车位...");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放锁资源
semaphore.release();
}
}, String.valueOf(i)).start();
}