CountDownLatch_CyclicBarrier_Semaphore 的使用
Java中的三大辅助类是CountDownLatch、CyclicBarrier和Semaphore,它们都位于java.util.concurrent包下。
- CountDownLatch:允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助。它被理解为一个减法计数器,每次有线程调用countDown()数量减一,当计数器变为0时,await()方法就结束,被唤醒,继续执行之后的代码。
- CyclicBarrier:允许一组线程全部等待彼此达到共同屏障点的同步辅助。在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。屏障被称为循环,因为它可以在等待的线程被释放之后重新使用。
- Semaphore:一个计数信号量。在概念上,信号量维持一组许可证。如果有必要,每个acquire()都会阻塞,直到许可证可用,然后才能使用它。每个release()添加许可证,潜在地释放阻塞获取方。
CountDownLatch
简述
CountDownLatch 是一个同步工具类,它通过一个计数器来实现。初始值为线程的数量,每当一个线程完成了自己的任务,计数器的值就相应得减1。当计数器到达0时,表示所有的线程都已执行完毕,然后在等待的线程就可以恢复执行任务
CountDownLatch的使用包括4个主要方法:
- countDown():每调用一次计数器值减1,直到count被减为0,代表所有线程全部执行完毕。
- getCount():获取当前计数器的值。
- await():等待计数器变为0,即等待所有异步线程执行完毕。
- CountDownLatch(int count):构造方法,设定计数器的初始值,一般需要多少个线程执行,count就设为几
使用
案例:6个乘客到下车了才能关门锁车
不加CountDownLatch:
java
public static void main(String[] args) {
for(int i =1;i <=6;i++){
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"下车了");
//countDownLatch.countDown();
},"乘客"+String.valueOf(i)).start();
}
```
System.out.println("main线程执行完毕:所有人都下车了,司机关门锁车");
执行结果:主线程已经提前执行完毕了,并没有等任务线程执行完再执行
css
乘客1下车了
乘客2下车了
main线程执行完毕:所有人都下车了,司机关门锁车
乘客3下车了
乘客5下车了
乘客4下车了
乘客6下车了
加了CountDownLatch后:
java
public static void main(String[] args) {
final 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();
}
try {
countDownLatch.await();
}catch (Exception e){
e.printStackTrace();
}
System.out.println("main线程执行完毕:所有人都下车了,司机关门锁车");
}
执行结果:任务全部执行完之后,主线程才往下执行,引入CountDownLatch后,我们能够控制住main方法的执行,这样能够保证前提任务的执行
css
乘客1下车了
乘客5下车了
乘客4下车了
乘客3下车了
乘客2下车了
乘客6下车了
main线程执行完毕:所有人都下车了,司机关门锁车
CyclicBarrier
简述
CyclicBarrier的字面意思是"可循环的屏障",可以理解为一种让多个线程相互等待的机制。就像一个屏障,所有线程必须到达这个屏障才能继续执行。当一个线程到达屏障时,它会等待其他线程到达。只有当所有线程都到达屏障时,它们才会一起继续执行。这个屏障是可以重复使用的,也就是说,一旦所有线程到达屏障并完成执行后,它们可以再次回到屏障处等待下一次的执行。
使用
案例:集齐7颗龙珠可以召唤神龙
java
**
* 定义一个循环屏障,参数1:需要累加的值,参数2 需要执行的方法
*/
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
System.out.println("集齐龙珠,召唤神龙");
});
for(int i=1;i<=7;i++){
final int tmpInt = i;
new Thread(()->{
System.out.println("线程"+Thread.currentThread().getName()+"\t"+"收集到第"+tmpInt+"颗龙珠");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
Semaphore
简述
Semaphore是一种计数信号量,用于管理一组资源。它允许n个任务同时访问某个资源,通过信号量许可证的方式来实现。每个任务在获取许可证之前都会被阻塞,直到有足够的许可证可用。当一个任务获取了一个许可证后,其他任务就可以继续运行。当所有任务都获取了足够的许可证后,它们就可以一起继续执行。信号量主要用于两个目的
- 一个是用于共享资源的互斥使用
- 另一个用于并发线程数的控制
使用
案例:模拟6辆汽车枪3个车位
Java
public static void main(String[] args) {
/**
* 初始化一个信号量为3,默认是false 非公平锁, 模拟3个停车位
*/
Semaphore semaphore = new Semaphore(3,false);
for(int i=1;i<=6;i++){
new Thread(()->{
try{
System.out.println(Thread.currentThread().getName()+"正在寻找车位");
TimeUnit.MILLISECONDS.sleep(200);
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"停进车位");
TimeUnit.MILLISECONDS.sleep(3000);
System.out.println(Thread.currentThread().getName()+"离开了车位");
}catch (Exception e){
e.printStackTrace();
}finally {
semaphore.release();
}
},"车辆"+String.valueOf(i)).start();
}
}
执行结果:
车辆1正在寻找车位
车辆3正在寻找车位
车辆2正在寻找车位
车辆5正在寻找车位
车辆6正在寻找车位
车辆4正在寻找车位
车辆4停进车位
车辆5停进车位
车辆3停进车位
车辆4离开了车位
车辆5离开了车位
车辆2停进车位
车辆1停进车位
车辆3离开了车位
车辆6停进车位
车辆2离开了车位
车辆1离开了车位
车辆6离开了车位
总结
CountDownLatch、CyclicBarrier和Semaphore都是Java中的同步工具,它们在多线程环境中用于协调和同步线程的执行。下面是它们的总结:
- CountDownLatch:
CountDownLatch是一个同步辅助工具,它允许一个或多个线程等待其他线程完成操作。它初始化一个计数器,线程执行完任务后调用countDown()方法,计数器减1,当计数器到达0时,等待的线程被唤醒继续执行。CountDownLatch只能使用一次,即只能完成一次同步操作。
使用场景:等待某个条件满足后继续执行,如等待前驱任务完成。
- CyclicBarrier:
CyclicBarrier是一个同步辅助工具,它允许一组线程相互等待,直到所有线程都到达一个公共屏障点(Barrier point)后再一起继续执行。类似于CountDownLatch,但它可以重复使用,当所有线程到达屏障后,屏障会重新设定为初始状态,等待下一轮的线程到达。CyclicBarrier可以定义一个Runnable对象,在所有线程到达屏障后执行。
使用场景:一组线程需要循环等待后一起执行,如多个线程需要共同完成一项任务。
- Semaphore:
Semaphore是一种计数信号量,用于管理一组资源。它维护一个计数器,表示可用资源的数量。当一个任务需要访问资源时,会调用acquire()方法尝试获取一个资源,如果计数器为0则阻塞,直到有足够的资源可用。当任务完成对资源的访问后,会调用release()方法释放资源,计数器加1。Semaphore可以控制并发访问资源的最大数量,防止过多的线程同时访问造成资源竞争或死锁等问题。
使用场景:控制并发访问资源的数量,如文件并发访问数限制、数据库连接池管理等。
总结:
CountDownLatch、CyclicBarrier和Semaphore都是用于多线程同步的工具。CountDownLatch用于等待某个条件满足后继续执行,CyclicBarrier用于一组线程循环等待后一起执行,Semaphore用于控制并发访问资源的数量。根据不同的场景选择合适的同步工具可以更好地管理多线程的执行和资源访问