Deadlock with CyclicBarrier?

363 Views Asked by At

I have an issue with the following piece of code for CyclicBarrier.

    MyJavaCyclicBarrierExample.java:::::::

            import java.util.Date; 
            import java.util.concurrent.BrokenBarrierException; 
            import java.util.concurrent.CyclicBarrier; 

            public class MyJavaCyclicBarrierExample { 

              public static void main(String[] args) { 

                  //3 threads are part of the barrier, ServiceOne, ServiceTwo and this main thread calling them. 

                  final CyclicBarrier barrier = new CyclicBarrier(2); 
                  Thread serviceOneThread = new Thread(new ServiceOne(barrier)); 
                  Thread serviceTwoThread = new Thread(new ServiceTwo(barrier)); 

                  System.out.println("Starting both the services at "+new Date()); 

                  serviceOneThread.start(); 
                  serviceTwoThread.start(); 

                  //Lets say main also has to do some work
                  try {
                      System.out.println("Main is going to do some work....");
                      Thread.sleep(10000);
                      System.out.println("Main has finished its work....");
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }

                  try {
                      System.out.println("Main is now going to wait at the barrier....");
                      barrier.await();
                      System.out.println("Main woken up at the barrier....");
                  } catch (InterruptedException e) { 
                      System.out.println("Main Thread interrupted!"); 
                      e.printStackTrace(); 
                  } catch (BrokenBarrierException e) { 
                      System.out.println("Main Thread interrupted!"); 
                      e.printStackTrace(); 
                  } 
                  System.out.println("Ending both the services at "+new Date()); 
              } 
            } 


        ServiceOne.java :::::::::
        import java.util.concurrent.BrokenBarrierException; 
        import java.util.concurrent.CyclicBarrier; 

        public class ServiceOne implements Runnable { 
            private final CyclicBarrier cyclicBarrier; 

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

            @Override
            public void run() { 
                System.out.println("Starting service One..."); 
                try { 
                    Thread.sleep(3000);   //assuming service one does some business logic here...
                } catch (InterruptedException e1) { 
                    e1.printStackTrace(); 
                } 
                System.out.println("Service One has finished its work... waiting for others..."); 
                try {
                        System.out.println("ServiceOne is now going to wait at the barrier....");
                        cyclicBarrier.await();      //Let's wait for the other threads at the cyclic barrier.
                        System.out.println("ServiceOne woken up at the barrier....");
                } catch (InterruptedException e) { 
                   System.out.println("Service one interrupted!"); 
                   e.printStackTrace(); 
                } catch (BrokenBarrierException e) { 
                   System.out.println("Service one interrupted!"); 
                   e.printStackTrace(); 
                } 
                System.out.println("The wait is over, lets complete Service Two!"); 
            } 
        } 



ServiceTwo.java:::::::::

import java.util.concurrent.BrokenBarrierException; 
import java.util.concurrent.CyclicBarrier; 
public class ServiceTwo implements Runnable { 
    private final CyclicBarrier cyclicBarrier; 
    public ServiceTwo(CyclicBarrier cyclicBarrier) { 
        this.cyclicBarrier = cyclicBarrier; 
    } 
    @Override 
    public void run() { 
        System.out.println("Starting service Two...."); 
        try { 
            Thread.sleep(2000);             //assuming service one does some business logic here...
        } catch (InterruptedException e1) { 
            e1.printStackTrace(); 
        } 
        System.out.println("Service Two has finished its work.. waiting for others..."); 
        try { 
            System.out.println("ServiceTwo is now going to wait at the barrier....");
            cyclicBarrier.await();                  //Let's wait for the other threads at the cyclic barrier.
            System.out.println("ServiceTwo woken up at the barrier....");
        } catch (InterruptedException e) { 
            System.out.println("Service one interrupted!"); 
            e.printStackTrace(); 
        } catch (BrokenBarrierException e) { 
            System.out.println("Service one interrupted!"); 
            e.printStackTrace(); 
        } 
        System.out.println("The wait is over, lets complete Service One!"); 
    } 
} 

My question is, when I run this code with CyclicBarrier at two levels, it always ends up into a deadlock it seems. Whereas, when I run the code with CyclicBarrier at level 1 or three, i.e. new CyclicBarrier(1) or new CyclicBarrier(3), it always completes successfully. What is the issue with level two then?

1

There are 1 best solutions below

0
On

CyclicBarrier is cyclic, which means it can be reused. When the barrier is initialized with argument 2, after tripped by serviceOneThread and serviceTwoThread, a new generation starts. The main thread can not trip it alone.

Maybe you need a CountDownLatch.