JUC中的常用辅助类(CountDownLatchCyclicBarrierSemaphore)
Posted XeonYu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC中的常用辅助类(CountDownLatchCyclicBarrierSemaphore)相关的知识,希望对你有一定的参考价值。
上一篇:
JUC中的 StampedLock
CountDownLatch
减法计数器,用来更方便的实现多线程的同步。
举个例子,android开发中,进入主页一般都会调好几个接口,我们需要在这几个接口都调用完毕后执行下一步操作,那我们肯定不会一个一个调用,肯定是要多个接口同时去调用,都调用完毕后再执行下一步操作,这种场景就非常适合用CountDownLatch来实现了。
CountDownLatch的方法并不多,用起来也比较简单
我们来直接用一用:
public static void main(String[] args) {
int num = 5;
System.out.println("主线程开始执行了");
/*创建一个给初始值的计数器*/
CountDownLatch countDownLatch = new CountDownLatch(num);
for (int i = 1; i <= num; i++) {
new Thread(() -> {
try {
TimeUnit.MILLISECONDS.sleep(1000);
System.out.println(Thread.currentThread().getName() + "执行完毕了");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
/*计数器减一*/
countDownLatch.countDown();
}
}, "Thread" + i).start();
}
try {
/*等待计数器的值减为0 否则阻塞住后面代码*/
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(num + "个接口都执行完毕了");
}
运行结果:
可以看到,很方便的就实现了多线程的同步。
CyclicBarrier
翻译过来是 循环屏障 的意思
常用方法如下:
先来看构造方法:
传两个参数,
- parties 表示在障碍被触发前需要调用await方法的线程数
- barrierAction 表示障碍触发时要执行的任务
再来看看await方法:
实际调用了dowait,再来看看dowait方法:
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
final Generation g = generation;
if (g.broken)
throw new BrokenBarrierException();
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
int index = --count;
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
Thread.currentThread().interrupt();
}
}
if (g.broken)
throw new BrokenBarrierException();
if (g != generation)
return index;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
代码太长了,这里就直接把源码复制过来了,可以看到,内部还是执行了减法,数值为0时,执行Runnable方法。
我们来简单用一用,以拼团为例,每三个人可以达成一个成团条件:
public static void main(String[] args) {
int num = 10;
int parties = 3;//屏障点
System.out.println("主线程开始执行了");
/*构造器传入一个达成条件要执行await的数量以及达到条件后要执行的任务*/
CyclicBarrier cyclicBarrier = new CyclicBarrier(parties, () -> System.out.println(Thread.currentThread().getName() + " 发现成团条件达成了...."));
for (int i = 1; i <= num; i++) {
int finalI = i;
new Thread(() -> {
try {
TimeUnit.MILLISECONDS.sleep(finalI * 1000L);
System.out.println(Thread.currentThread().getName() + "开始拼团");
/*调用一下await 就会触发*/
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
}, "线程" + i).start();
}
System.out.println("主线程执行到这了......");
}
来看一看运行结果:
可以看到,CyclicBarrier 中的await方法不会阻塞住主线程。每当条件达成时,达到触发条件的当前线程就会执行一遍Runnable。但是如果没有达成条件,则会一直处于等待状态。
Semaphore
翻译叫做 信号量,通常我们叫做 计数信号量。
主要用来限制多线程下的并发数量(限流)。
先来看看有哪些方法:
Semaphore维护了我们指定数量的许可证,通过acquire方法获取许可证,当许可证数量为0时,其他线程处于等待状态,通过Release方法释放(归还)许可证。归还后其他线程可以通过获取许可证去执行。
简单用一用:
public static void main(String[] args) {
/*指定许可证的数量为3*/
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
/*获取许可证*/
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "拿到了许可证");
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName() + "====释放了许可证");
/*释放许可证*/
semaphore.release();
}
}, "线程" + i).start();
}
}
运行结果如下:
可以看到,同时只会有三个线程执行。
如果你觉得本文对你有帮助,麻烦动动手指顶一下,可以帮助到更多的开发者,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!
以上是关于JUC中的常用辅助类(CountDownLatchCyclicBarrierSemaphore)的主要内容,如果未能解决你的问题,请参考以下文章
JUC常用同步工具类——CountDownLatch,CyclicBarrier,Semaphore
重点知识学习(8.3)--[JUC常用类 || Java中的14把锁 || 对象头 || Synchronized 与 ReentrantLock]