Application hangs when I invoke join inside CyclicBarrier callback

159 Views Asked by At

I have the following method test where I start threads:

public static void main(String[] args) throws InterruptedException {
        List<Thread> threads = new ArrayList<>();
        final CyclicBarrier cyclicBarrier = new CyclicBarrier(1);
        Thread thread = new Thread(new CallbackThread(cyclicBarrier, threads));
        threads.add(thread);
        thread.start();          
    }

CallBack thread looks like this:

class CallbackThread implements Runnable {
    CyclicBarrier cyclicBarrier;
    List<Thread> threads;

    CallbackThread(CyclicBarrier cyclicBarrier, List<Thread> threads) {
        this.cyclicBarrier = cyclicBarrier;
        this.threads = threads;
    }

    @Override
    public void run() {
        try {
            cyclicBarrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (BrokenBarrierException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        System.out.println("Threads started");
        for (Thread thread1 : threads) {
            try {
                thread1.join();
            } catch (InterruptedException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
        System.out.println("Threads finished");

    }
}

When I run application I see following output:

Threads started

and application hangs.

I don understand why.

If to replace join logic to main method - all goods well.

public static void main(String[] args) throws InterruptedException {
        List<Thread> threads = new ArrayList<>();
        final CyclicBarrier cyclicBarrier = new CyclicBarrier(1);
        Thread thread = new Thread(new CallbackThread(cyclicBarrier, threads));
        threads.add(thread);
        thread.start();
        for (Thread thread1 : threads) {
            try {
                thread1.join();
            } catch (InterruptedException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
        System.out.println("Threads finished");

    }

Can you explain this difference.
IMHO it should work same.

2

There are 2 best solutions below

1
On BEST ANSWER

The code from your first example calls join on its own thread. You add it to the list and the thread iterates over the list and joins every thread inside the list.

1
On

You are joining on self. That's why the program never ends.

When you call the join() from Main thread, then main thread is trying to join the thread it created which is CallableThread. So it is proper.

But when you join in CallableThread, then you are passing threads[] which contains the reference to itself. So it is joining itself, which will not end.