1CountDownLatch(倒计时门闩)
CountDownLatch 一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
闭锁可以延迟线程的进度直到其到达终止状态,闭锁可以用来确保某些活动直到其他活动都完成才继续执行:
- 确保某个计算在其需要的所有资源都被初始化之后才继续执行;
- 确保某个服务在其依赖的所有其他服务都已经启动之后才启动;
- 等待直到某个操作所有参与者都准备就绪再继续执行
CountDownLatch 内部维护了⼀个计数器,只有当计数器==0时,某些线程才会停止阻塞,开始执行。
CountDownLatch 主要有两个方法, countDown() 来让计数器-1, await() 来让线程阻塞。当 count==0 时,阻塞线程自动唤醒。
案例 班长关门:main线程是班长,6个线程是学生。只有6个线程运行完毕,都离开教室后,main线程班长才会关教室门
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 16; i++) {
int temp = i;
new Thread(()->{
try { TimeUnit.SECONDS.sleep(temp); } catch (InterruptedException e) {e.printStackTrace(); }
System.out.println("同学离开了教室");
countDownLatch.countDown();
}, String.valueOf(i)).start();
}
//班长等待关门
countDownLatch.await();
System.out.println(Thread.currentThread().getName() +"班长最后最后关教室门...");
}
}
2CyclicBarrier(篱栅)
CyclicBarrier 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
CountDownLatch 是减,而 CyclicBarrier 是加,理解了 CountDownLatch , CyclicBarrier 就很容易。比如召集7颗⻰珠才能召唤神龙,拼团发货
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7, ()->{
System.out.println("======龙珠收齐召唤神龙....");
});
for (int i = 1; i <= 7; i++) {
int temp = i;
new Thread(()->{
try { TimeUnit.SECONDS.sleep(temp); } catch (InterruptedException e) {e.printStackTrace(); }
System.out.println("收集第"+temp+"龙珠...");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}, String.valueOf(i)).start();
}
}
}
去掉sleep方法运行结果为(各个线程不用互相等待)
3Semaphore(信号灯)
一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。
Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。
CountDownLatch 的问题是不能复用。比如 count=3 ,那么减到0,就不能继续操作了。而Semaphore 可以解决这个问题,比如6辆⻋3个停⻋位,对于 CountDownLatch 只能停3辆车,而Semaphore 可以停6辆⻋,车位空出来后,其它⻋可以占有,这就涉及到了Semaphore.accquire() 和 Semaphore.release() 方法。
/**
* 在信号量上我们定义两种操作:
* acquire(获取)当一个线程调用acquire操作时,他要么通过成功获取信号量(信号量减1),要么一直等待下去,直到有线程释放信号量,或超时。
* release(释放)实际上会将信号量加1,然后唤醒等待的线程。
*
* 信号量主要用于两个目的,一个是用于多个共享资源的互斥使用,另一个用于并发线程数的控制
*/
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <= 7; i++) {
final int temp = i;
new Thread(()->{
//占有资源
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"抢到了车位...");
try { TimeUnit.SECONDS.sleep(temp); } catch (InterruptedException e) {e.printStackTrace(); }
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName()+"===释放了车位...");
semaphore.release();
}
}, String.valueOf(i)).start();
}
}
}