前言
昨天我们分享了多线程里面的一个计数器countDownLatch,它的主要作用是控制线程执行顺序,确保上一个操作完成后,下一个线程才能启动运行,但是某些情况下countDownLatch并不能满足我们的需求,比如执行A线程10次后,我们需要执行B线程,然后再执行A线程10次,循环往复,为了应付这样的应用场景,jdk也为我们提供了相应的解决方案——另一个计数器CyclicBarrier,今天我们就一起来看看吧。
CyclicBarrier
CyclicBarrier中文的意思是循环格栅,循环屏障,循环关卡,循环分界线,我觉得叫循环分界线应该更好理解,因为它起的作用就是分隔。它和countDownLatch一样,也是jdk1.5引入的。它的作用有点像触发器,当达到设定的数值时,我们可以触发一个操作。
这样干巴巴讲,大家可能想不来,那我们先看这样一段示例代码:
public class Example { static AtomicInteger count = new AtomicInteger(0); public static void main(String[] args) { AtomicInteger count2 = new AtomicInteger(0); CyclicBarrier cyclicBarrier = new CyclicBarrier(10, () -> { System.out.println("多线程循环完成" + count2.getAndIncrement()); }); for (int i = 0; i < 100; i++) { new Thread(new Task(cyclicBarrier)).start(); } } static class Task implements Runnable { private final CyclicBarrier cyclicBarrier; public Task(CyclicBarrier cyclicBarrier) { this.cyclicBarrier = cyclicBarrier; } @Override public void run() { try { Thread.sleep(1000); synchronized (count) { System.out.println(count.getAndIncrement()); } cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } }
上面的代码中,我们定义了一个原子整数,初始值为0;
我们定义了一个cyclicBarrier,触发值我们设定为10,在触发操作里我们打印提示信息;
我们还定义了一个线程,在线程内部我们对原子整数count加一并打印。
然后我们在main方法中循环启动100个线程,运行上面的代码,结果大致如下:
根据运行结果,我们可以看出来,count每增加10,也就是启动十个线程,会触发CyclicBarrier中我们定义的操作,这个数值也就是我们在CyclicBarrier指定的触发值。
如果我们把触发值设置为5,那应该每隔5次就会打印一次,我们验证下:
事实也确实如此,我想到这里大家应该都清楚CyclicBarrier的用法了吧。
关于CyclicBarrier的构造方法我在多说两句,CyclicBarrier有两种构造方法,但是第二种最常用,也就是我们演示的这种:
入参有两个,一个就是触发次数,一个就是触发操作。
另外还需要注意的是,它的await()方法和countDownLatch的方法是不一样的,在它的await()方法中,有一个--count的操作,也就是每次都会把我们设定的数值减一,直至为零,如果--count为0,它就会触发我们的barrierAction:
对于它的应用场景,我想大家应该能够想到很多,比如固定条数保存数据,多线程提交保存操作,然后达到固定条数提交数据库保存,当然还有很多其他的应用场景,大家可以结合自己的应用需求,好好想一想。
总结
虽然一开始我拿countDownLatch和CyclicBarrier做比较,但是事实上,它们两个不具备任何可比性,而且适用的场景也是不一样的。countDownLatch核心方法是countDown和aWait,主要用于控制线程执行顺序;CyclicBarrier主要用于有回调需求的场景,而且它的await方法也不一样,但是它们都很有用。
最后,希望大家多动手实现,多练习,毕竟学习这件事,还是实践出真知,多线程想要学的好,juc下面的类少不了,一起加油吧!