Semaphore、CountdownLatch、CyclicBarrier

一、Semaphore

Semaphore可以用作信号量,控制同时访问共享资源的线程数量上限!


public static void main(String[] args) {
	 // 1. 创建 semaphore 对象
	 Semaphore semaphore = new Semaphore(3);
	 // 2. 10个线程同时运行
	 for (int i = 0; i < 10; i++) {
		 new Thread(() -> {
			 // 3. 获取许可
			 try {
			     //每个线程首先都会尝试获取信号量
				 semaphore.acquire();
				 } catch (InterruptedException e) {
				 e.printStackTrace();
				 }
			 try {
				 log.debug("running...");
				 sleep(1);
				 log.debug("end...");
				 } finally {
				 // 4. 释放许可
				 semaphore.release();
				 }
		 }).start();
 }
 }

在这里插入图片描述

二、CountdownLatch

CountdownLatch可以辅助线程进行同步协作,通过它可以实现让某个线程等待其它多个线程完成任务之后才能继续向下执行。其中构造参数用来初始化等待计数值,await() 用来等待计数归零,countDown() 用来让计数减一!


public static void main(String[] args) throws InterruptedException {
 	CountDownLatch latch = new CountDownLatch(3);
 	new Thread(() -> {
 		log.debug("begin...");
		sleep(1);
 		latch.countDown();
 		log.debug("end...{}", latch.getCount());
 	}).start();
 	new Thread(() -> {
		 log.debug("begin...");
		 sleep(2);
		 latch.countDown();
		 log.debug("end...{}", latch.getCount());
	 }).start();
 	new Thread(() -> {
		 log.debug("begin...");
		 sleep(1.5);
		 latch.countDown();
		 log.debug("end...{}", latch.getCount());
 	}).start();
 log.debug("waiting...");
 latch.await();
 log.debug("wait end...");
}

在这里插入图片描述
CountdownLatch还可以配合线程池使用!


public static void main(String[] args) throws InterruptedException {
 	CountDownLatch latch = new CountDownLatch(3);
 	ExecutorService service = Executors.newFixedThreadPool(4);
 	service.submit(() -> {
		 log.debug("begin...");
		 sleep(1);
		 latch.countDown();
		 log.debug("end...{}", latch.getCount());
 	});
 	service.submit(() -> {
		 log.debug("begin...");
		 sleep(1.5);
		 latch.countDown();
		 log.debug("end...{}", latch.getCount());
 	});
 	service.submit(() -> {
		 log.debug("begin...");
		 sleep(2);
		 latch.countDown();
		 log.debug("end...{}", latch.getCount());
 	});
 	service.submit(()->{
		 try {
		 log.debug("waiting...");
		 latch.await();
		 log.debug("wait end...");
		 } catch (InterruptedException e) {
		 e.printStackTrace();
 		 }
 	});
}

在这里插入图片描述

三、CyclicBarrier

CyclicBarrier可以用来辅助线程同步协作,通过它可以实现让一组线程相互等待至某个状态之后再全部同时执行。构造时设置『计数个数』,每个线程执行到某个需要“同步”的时刻调用 await() 方法进行等待,当等待的线程数满足『计数个数』时,继续向下执行!它要做的事情是,让一组线程到达某个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。

CyclicBarrier cb = new CyclicBarrier(2); // 个数为2时才会继续执行

new Thread(()->{
 	System.out.println("线程1开始.."+new Date());
 	try {
 			cb.await(); // 当个数不足时,等待
 	} catch (InterruptedException | BrokenBarrierException e) {
 		e.printStackTrace();
 	}
	System.out.println("线程1继续向下运行..."+new Date());
}).start();

new Thread(()->{
 	System.out.println("线程2开始.."+new Date());
 	try { Thread.sleep(2000); } catch (InterruptedException e) { }
 	try {
 			cb.await(); // 2 秒后,线程个数够2,继续运行
 		} catch (InterruptedException | BrokenBarrierException e) {
 			e.printStackTrace();
 		}
 		System.out.println("线程2继续向下运行..."+new Date());
}).start();

注意 CyclicBarrier 与 CountDownLatch 的主要区别在于 CyclicBarrier 是可以重用的 CyclicBarrier 可以被比喻为『人满发车』

四、Semaphore、CountdownLatch和CyclicBarrier区别

区别SemaphoreCountdownLatchCyclicBarrier
可重用次数单次单次循环使用(多次)
线程阻塞超过许可数,线程会阻塞单个线程被阻塞,以等待其它线程执行完毕多个线程之间相互阻塞等待
使用场景数据库连接池计数器拆分任务的并行计算

五、总结

    CountDownLatch 和 CyclicBarrier 都能够实现线程之间的等待,只不过它们侧重点不同;CountDownLatch 一般用于某个线程等待其它若干个其他线程执行完任务之后才继续执行的状况;而 CyclicBarrier 一般用于一组线程互相等待至某个状态再同时执行的情况;CountDownLatch 是不能够重用的,而 CyclicBarrier 是可以重用的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Malax

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值