为什么 CyclicBarrier.await(int timeout,TimeUnit unit) 没有在这里抛出 TimeOutException?

问题描述

话费便宜。显示代码

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 已经达到了花费 2 秒的屏障点。同时,最后一个线程在等待 2 秒后启动。1 秒后,0 到 3 线程达到指定的超时时间,其中 4 线程仍然执行自己的代码。这里的问题是:为什么 CyclicBarrier.await(int timeout,TimeUnit unit) 没有在这里抛出 TimeOutException

解决方法

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

这是正确的。

同时等待 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();
}
,

你似乎认为线程启动时超时就开始了:

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

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 的超时

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...