执行结果
- 23:46:34.698 [main] ERROR com.test – 司机师傅人够一车再发车,等会人吧…
- 23:46:34.757 [zoo1] ERROR com.test – 看会手机的乘客上车啦
- 23:46:34.758 [zoo3] ERROR com.test – 看会售票员的乘客上车啦
- 23:46:34.757 [zoo0] ERROR com.test – 看会书的乘客上车啦
- 23:46:34.759 [zoo1] ERROR com.test – 车上好无聊啊,看会手机吧!
- 23:46:34.759 [zoo3] ERROR com.test – 车上好无聊啊,看会售票员吧!
- 23:46:34.757 [zoo2] ERROR com.test – 看会风景的乘客上车啦
- 23:46:34.759 [zoo0] ERROR com.test – 车上好无聊啊,看会书吧!
- 23:46:34.759 [zoo2] ERROR com.test – 车上好无聊啊,看会风景吧!
- 23:46:34.759 [main] ERROR com.test – 人够了,起飞!
司机师傅(主线程)要等上了4个乘客以后才发车(等待4个子线程完成完成某件事以后调用countDown方法),而乘客上车(调用countDown)以后该做自己的事还做自己的事情,不会因为上了车就傻呆呆的什么都不干了(不会因为调用了countDown而阻塞自身)。等司机师傅看人够了(到达设定阈值),就发车了。
闭锁总结:
- 主线程调用await后会阻塞等待其他子线程调用countDown方法将设定阈值减至0,然后在继续执行。
- 而子线程不会因为调用了countDown方法而阻塞
栅栏
栅栏(CyclicBarrier)官方解释:
- /**
- * A synchronization aid that allows a set of threads to all wait for
- * each other to reach a common barrier point. CyclicBarriers are
- * useful in programs involving a fixed sized party of threads that
- * must occasionally wait for each other. The barrier is called
- * <em>cyclic</em> because it can be re-used after the waiting threads
- * are released.
- */
- 同步帮助,允许一组线程互相等待,以达到共同的障碍点。 CyclicBarriers在涉及固定大小的线程方的程序中很有用,这些线程有时必须互相等待。该屏障称为<em> cyclic </ em>,因为它可以在释放等待线程后重新使用。
从类注释上我们可以大致了解到,他是运用在一组,也即是多个线程中的,当所有线程到达某个状态前一直阻塞,直到所有线程都达到后再继续执行。而且是可以重复使用的。
上面的描述还是太晦涩了,还是举个栗子:
我们小时候学校都组织过春游,规定好地点,等人到齐了就一起进去玩。写了个简单的例子,看这种场景栅栏是怎么工作的
- public static void main(String[] args) {
- List<Boy> list = new ArrayList<>();
- Boy boy1 = new Boy("看老虎");
- Boy boy2 = new Boy("看猩猩");
- Boy boy3 = new Boy("看狮子");
- Boy boy4 = new Boy("看售票员");
- list.add(boy1);
- list.add(boy2);
- list.add(boy3);
- list.add(boy4);
- ThreadPoolExecutor executor = new ThreadPoolExecutor(20, 200, 1000, TimeUnit.SECONDS, new LinkedBlockingQueue<>(3), new ThreadFactory() {
- private ThreadGroup group = (null == System.getSecurityManager() ? Thread.currentThread().getThreadGroup() : System.getSecurityManager().getThreadGroup());
- private AtomicInteger num = new AtomicInteger();
- @Override
- public Thread newThread(Runnable r) {
- Thread thread = new Thread(group, r,"zoo" + num.getAndIncrement(),0);
- thread.setDaemon(false);
- return thread;
- }
- }, new ThreadPoolExecutor.CallerRunsPolicy());
- //初始化栅栏,设置障碍点阈值
- CyclicBarrier cyclicBarrier = new CyclicBarrier(list.size());
- for (Boy boy : list) {
- executor.execute(()->gotoZOO(boy,cyclicBarrier));
- }
- }
- private static void gotoZOO(Boy boy,CyclicBarrier cyclicBarrier){
- log.error("人还没到齐呢,等一下吧,{}的小男孩开始等待",boy.getWhere());
- try {
- cyclicBarrier.await();
- log.error("{}",boy.goWhere());
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- static class Boy{
- private String where;
- public Boy(String where) {
- this.where = where;
- }
- public String getWhere() {
- return where;
- }
- public String goWhere() {
- return "人到齐了,我要去"+where+"啦!";
- }
- }
执行结果:
- 22:05:59.476 [zoo2] ERROR com.test – 人还没到齐呢,等一下吧,看狮子的小男孩开始等待
- 22:05:59.477 [zoo1] ERROR com.test – 人还没到齐呢,等一下吧,看猩猩的小男孩开始等待
- 22:05:59.477 [zoo0] ERROR com.test – 人还没到齐呢,等一下吧,看老虎的小男孩开始等待
- 22:05:59.476 [zoo3] ERROR com.test – 人还没到齐呢,等一下吧,看售票员的小男孩开始等待
- 22:05:59.484 [zoo0] ERROR com.test – 人到齐了,我要去看老虎啦!
- 22:05:59.484 [zoo2] ERROR com.test – 人到齐了,我要去看狮子啦!
- 22:05:59.484 [zoo3] ERROR com.test – 人到齐了,我要去看售票员啦!
- 22:05:59.484 [zoo1] ERROR com.test – 人到齐了,我要去看猩猩啦!
我们可以发现前三个小男孩在到达以后都没有进到动物园里,而是直到第四个小男孩来到以后,四个小男孩才进入动物园,在此之前每来一个小朋友就多一个小朋友等待(每个线程调用await方法),直到等待所有人到齐(线程阻塞等待达到栅栏障碍点4),各个小男孩再去继续进入动物园看动物(各线程继续执行自己的任务)。就像是动物园大门的栅栏,买的是团体票,每次必须人到齐才放开让小朋友进去一样。