【问题标题】:Why did CyclicBarrier.await(int timeout,TimeUnit unit) didn't throw TimeOutException here?为什么 CyclicBarrier.await(int timeout,TimeUnit unit) 没有在这里抛出 TimeOutException?
【发布时间】:2021-09-03 19:04:36
【问题描述】:

谈话很便宜。显示代码。

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

【问题讨论】:

    标签: java cyclicbarrier


    【解决方案1】:

    你好像认为线程启动时超时就开始了:

    线程 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 的超时时间

    【讨论】:

    • 谢谢你的回答!线程到达那个点需要多长时间都没关系 - 从调用方法 cyclicBarrier.await() 的那一刻起超时是 3 秒。我是还是有点迷糊。从线程4调用cyclicBarrier.await()开始算起3秒吗?如果是,那就是正确答案~
    • @KevinWyen 我已经更新了我的答案,提供了有关操作时间的更多详细信息
    【解决方案2】:

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

    这是正确的。

    在同一时间,最后一个线程在等待 2 秒后启动。

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

    但线程 4 在 run 方法中仅休眠 2 秒(距离TimeoutException 仅剩 1 秒)。

    当涉及到await 时,它是最后一个线程 - 所以它不必再等待了。因此,屏障动作开始运行,其他动作被解除 - 来自 javadoc,

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

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

    try {
        TimeUnit.SECONDS.sleep(4);
        new MyCyclicBarrier(cyclicBarrierWithRunnable).start();
    } catch (InterruptedException e) {
         e.printStackTrace();
    }
    

    【讨论】:

    • 是的。我看到Javadoc说如果当前线程是最后一个到达的线程......那么当前线程在允许其他线程继续之前运行该操作。您也可以尝试在构造中提供一个空屏障动作。这也不会引发超时异常:(这就是为什么让我困惑了好几天)。
    • 至于程序最后休眠 4 秒就超时了,我并不是要求程序抛出 Timeout 异常(如果是 3 秒就好了)。我只是不明白为什么我在使用 await(int timeout, timeUnit unit) 时线程超时而没有抛出 Timeout Exception。感谢您的耐心等待,期待您的回复:)
    • 事实上没有线程超过休眠 3 秒的限制。最后一个线程(线程 4)在其他线程等待 2 秒后到达 await (作为await 的一部分)。屏障动作在一秒钟内完成,从而解除了 3 个线程的阻塞。
    猜你喜欢
    • 1970-01-01
    • 2018-01-05
    • 2019-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-06
    • 1970-01-01
    • 2013-05-20
    相关资源
    最近更新 更多