CyclicBarrier唤醒线程的时机以及唤醒个数

来源:10-8 循环栅栏的作用

深海的星星15138

2020-05-04

老师,有个问题,当创建CyclicBarrier时传入了一个runnable,那么在唤醒线程时,是先执行完runnable再去唤醒,还是同时进行?我运行的结果好像是先去执行完runnable再去唤醒。但是唤醒几个呢?您课上讲到的如果CyclicBarrier的计数大小为5,而我们有10个线程,那它会5个一波5个一波。但我运行的结果好像不是这样。例如下面的代码:

public class CyclicBarrierDemo {
    static class Task implements Runnable {
        private int id;
        private CyclicBarrier cyclicBarrier;

        public Task(int id, CyclicBarrier cyclicBarrier) {
            this.id = id;
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            try {
                System.out.println("线程" + id + "开始执行任务...");
                Thread.sleep((long) (Math.random() * 5000));
                System.out.println("线程" + id + "执行完部分任务, 到达集合点, 开始等待其他线程到达");
                cyclicBarrier.await();
                System.out.println("线程" + id + "从集合点出发, 开始执行剩下的任务...");
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("人满了, 大家统一出发, 倒计时10秒...");
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        
        for (int i = 0; i < 10; i++) {
            new Thread(new Task(i + 1, cyclicBarrier)).start();
        }
    }
}

它的运行结果总是这样的,10个线程先后抵达“集合点”,第一次打开栅栏发生在10个线程抵达集合点之前(因为栅栏要等待10秒而线程抵达集合点最多要5秒),第一次打开栅栏之后放行一个线程,第二次打开栅栏会放行9个线程。为什么是这种结果呢?

写回答

1回答

深海的星星15138

提问者

2020-05-04

内容太多,可能不方便看。总结一下问题就是,在一次计数完成准备唤醒线程时,如果在传入CyclicBarrier的runnable执行完成之前,就又有线程到达了栅栏位置,这时会怎么办?

1
1
悟空
CyclicBarrier的runnable是在栅栏打开时执行,由最后一个到达集合点的线程执行,这一点可以用Thread的name来验证。 你的问题很好,我觉得想回答这个问题,可以通过实验现象来得出结论。 如果在传入CyclicBarrier的runnable执行完成之前,就又有线程到达了栅栏位置,我的实验现象和你一样。 我看到的现象是,除了每一批最后一个到达集合点的线程之外,其他的线程会等第二批runnable执行完之后,才会放行。
2020-05-06
共1条回复

深度解密Java并发工具,精通JUC,成为并发多面手

JUC全方位讲解,构建并发工具类知识体系

1599 学习 · 573 问题

查看课程