简体   繁体   中英

Why did CyclicBarrier.await(int timeout,TimeUnit unit) didn't throw TimeOutException here?

Talk is cheap. Show the code.

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();
                }
            }
        }
    }
}

Output:

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

I am searching for a long time on net. But no similar answer. Please help or try to give some ideas! And I just start to learn CyclicBarrier .

I wonder if I have misunderstood CyclicBarrier.await(int timeout,TimeUnit unit) . Threads 0 through 3 have already reached the barrier point that cost 2s.In the same time the final Thread started after 2s of waiting.After 1 second number 0 to 3 Threads reach the specified timeout which number 4 thread still excuted its own code. Here is the question: Why did CyclicBarrier.await(int timeout, TimeUnit unit) didn't throw TimeOutException here?

Threads 0 through 3 have already reached the Barrier point that cost 2s.

This is correct.

In the same time the final Thread started after 2s of waiting.

Correct. Note, by the time this thread starts, other 4 threads are awaiting the CB (3 secs timeout ie, we have 3 secs until a TimeoutException can occur).

But thread 4 sleeps for only 2 seconds in the run method (we still have only 1 sec until the TimeoutException ).

When it comes to await , it is the last thread - so it doesn't have to wait anymore. Hence the barrier action gets run and others are unblocked - from javadoc,

If the current thread is the last thread to arrive, and a non-null barrier action was supplied in the constructor, then the current thread runs the action before allowing the other threads to continue.

If you make sleep for four seconds before starting thread-4, you would get a TimeoutException .

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

You seem to think that the timeout starts when the thread starts:

Threads 0 through 3 have already reached the Barrier point that cost 2s.

After 1 second number 0 to 3 Threads reach the specified timeout

This is wrong. When you call

cyclicBarrier.await(3,TimeUnit.SECONDS);

it doesn't matter how long it took the threads to reach that point - the timeout is 3 seconds from the moment the method cyclicBarrier.await() is called.

Since thread 4 has only an additional delay of 2 seconds it still arrives in time.


To clarify further this is what the timeline looks like:

  • t=0s

    • main() creates the CyclicBarrier and starts threads 0 to 3
    • the threads 0 to 3 start and call TimeUnit.SECONDS.sleep(2);
    • main calls TimeUnit.SECONDS.sleep(2);
  • t=2s

    • main() starts thread 4
    • the threads 0 to 3 awake, print out something and then call cyclicBarrier.await(3,TimeUnit.SECONDS); which means that they will be interrupted at t=5s (t=2s + 3s)
    • thread 4 stars and calls TimeUnit.SECONDS.sleep(2);
  • t=4s

    • thread 4 awakes, prints out something and then calls cyclicBarrier.await(3,TimeUnit.SECONDS); .
    • since now all threads are within cyclicBarrier.await(3,TimeUnit.SECONDS); , the condition for the CyclicBarrier is fulfilled and all threads continue
    • the timeout for thread 4 doesn't get used (because it is the last thread to reach the CyclicBarrier )
    • for threads 0 to 3 the timeout at t=5s is never reached

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM