1

说话便宜。显示代码。

MyCyclicBarrier.java

public class MyCyclicBarrier extends Thread{
    private CyclicBarrier cyclicBarrier;

    public MyCyclicBarrier(CyclicBarrier cyclicBarrier) {
        this.cyclicBarrier = cyclicBarrier;
    }

    @Override
    public void run() {
        System.out.println("Thread start." + Thread.currentThread().getName());
        try {
            TimeUnit.SECONDS.sleep(2);  //biz code
            System.out.println("Thread "+Thread.currentThread().getName()+" is waiting for the other Threads."+
                    "\n\t\t\t\tIt's parties is "+cyclicBarrier.getParties()+
                    "\n\t\t\t\tWaiting for "+cyclicBarrier.getNumberWaiting()+" Threads");
            cyclicBarrier.await(3,TimeUnit.SECONDS);
        } catch (InterruptedException | BrokenBarrierException | TimeoutException e) {
            e.printStackTrace();
        }
        System.out.println("Thread end."+Thread.currentThread().getName());
    }
}

TestCyclicbarrier.java

public class TestCyclicbarrier1 {
    public static void main(String[] args) {
        int length = 5;
        long start = System.currentTimeMillis();
        CyclicBarrier cyclicBarrierWithRunnable = new CyclicBarrier(length, () -> {
            System.out.println("the final reach Thread is " + Thread.currentThread().getName());
            long end = System.currentTimeMillis();
            System.out.println("cost totally :" + (end - start) / 1000 + "s");
        });
        for (int i = 0; i < length; i++) {
            if (i != 4) {
                new MyCyclicBarrier(cyclicBarrierWithRunnable).start();
            } else {
                try {
                    TimeUnit.SECONDS.sleep(2);
                    new MyCyclicBarrier(cyclicBarrierWithRunnable).start();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

输出:

Thread start.Thread-1
Thread start.Thread-0
Thread start.Thread-2
Thread start.Thread-3
Thread Thread-0 is waiting for the other Threads.
                It's parties is 5
                Waiting for 0 Threads
Thread Thread-3 is waiting for the other Threads.
                It's parties is 5
                Waiting for 0 Threads
Thread start.Thread-4
Thread Thread-1 is waiting for the other Threads.
                It's parties is 5
                Waiting for 0 Threads
Thread Thread-2 is waiting for the other Threads.
                It's parties is 5
                Waiting for 1 Threads
Thread Thread-4 is waiting for the other Threads.
                It's parties is 5
                Waiting for 4 Threads
the final reach Thread is Thread-4
cost totally :4s
Thread end.Thread-4
Thread end.Thread-0
Thread end.Thread-3
Thread end.Thread-2
Thread end.Thread-1

我在网上找了很久。但没有类似的答案。请帮助或尝试给出一些想法!而我刚刚开始学习CyclicBarrier

我想知道我是否误解了CyclicBarrier.await(int timeout,TimeUnit unit)。线程 0 到 3 已经到达了花费 2s 的障碍点。同时,最后一个线程在等待 2s 后启动。1 秒后,0 到 3 线程达到指定的超时时间,4 号线程仍然执行自己的代码。问题来了:为什么没有CyclicBarrier.await(int timeout, TimeUnit unit) 扔到TimeOutException这里?

4

2 回答 2

0

您似乎认为超时在线程启动时开始:

线程 0 到 3 已经到达了花费 2s 的障碍点。

1 秒后数字 0 到 3 线程达到指定超时

这是错误的。你打电话时

cyclicBarrier.await(3,TimeUnit.SECONDS);

线程到达该点需要多长时间都没关系 - 从cyclicBarrier.await()调用方法的那一刻起超时是 3 秒。

由于线程 4 只有 2 秒的额外延迟,它仍然及时到达。


为了进一步澄清,这是时间线的样子:

  • t=0s

    • main()创建CyclicBarrier并启动线程 0 到 3
    • 线程 0 到 3 启动并调用TimeUnit.SECONDS.sleep(2);
    • 主要电话TimeUnit.SECONDS.sleep(2);
  • t=2s

    • main()启动线程 4
    • 线程 0 到 3 唤醒,打印出一些东西然后调用cyclicBarrier.await(3,TimeUnit.SECONDS);,这意味着它们将在 t=5s (t=2s + 3s) 被中断
    • 线程 4 星和调用TimeUnit.SECONDS.sleep(2);
  • t=4s

    • 线程 4 唤醒,打印出一些东西,然后调用cyclicBarrier.await(3,TimeUnit.SECONDS);.
    • 由于现在所有线程都在cyclicBarrier.await(3,TimeUnit.SECONDS);其中,因此满足条件CyclicBarrier并且所有线程继续
    • 线程 4 的超时没有被使用(因为它是到达的最后一个线程CyclicBarrier
    • 对于线程 0 到 3,永远不会达到 t=5s 的超时
于 2021-06-19T10:56:00.770 回答
0

线程 0 到 3 已经到达了花费 2s 的障碍点。

这是对的。

同时,最终线程在等待 2 秒后启动。

正确的。请注意,当这个线程启动时,其他 4 个线程正在等待 CB(3 秒超时,即,我们有 3 秒的时间直到 aTimeoutException发生)。

但是线程 4 在run方法中只休眠了 2 秒(我们仍然只有 1 秒的时间TimeoutException)。

说到await,它是最后一个线程- 所以它不必再等待了。因此,屏障动作开始运行,其他动作被解锁 - 从 javadoc,

如果当前线程是最后到达的线程,并且在构造函数中提供了非空屏障动作,则当前线程在允许其他线程继续之前运行该动作。

如果你在启动线程 4 之前让睡眠四秒钟,你会得到一个TimeoutException.

try {
    TimeUnit.SECONDS.sleep(4);
    new MyCyclicBarrier(cyclicBarrierWithRunnable).start();
} catch (InterruptedException e) {
     e.printStackTrace();
}
于 2021-06-19T09:43:02.867 回答