Search code examples
javamultithreadingjava.util.concurrent

Synchronize Three Threads


Was asked this question in an interview , tried to solve it ... but not successful. I thought of using CyclicBarrier

There are three threads T1 prints 1,4,7... T2 prints 2,5,8... and T3 prints 3,6,9 …. How do you synchronize these three to print sequence 1,2,3,4,5,6,7,8,9....

I tried writing & running the following code

public class CyclicBarrierTest {
    public static void main(String[] args) {
        CyclicBarrier cBarrier = new CyclicBarrier(3);
        new Thread(new ThreadOne(cBarrier,1,10,"One")).start();
        new Thread(new ThreadOne(cBarrier,2,10,"Two")).start();
        new Thread(new ThreadOne(cBarrier,3,10,"Three")).start();
    }
}

class ThreadOne implements Runnable {
    private CyclicBarrier cb;
    private String name;
    private int startCounter;
    private int numOfPrints;

    public ThreadOne(CyclicBarrier cb, int startCounter,int numOfPrints,String name) {
        this.cb = cb;
        this.startCounter=startCounter;
        this.numOfPrints=numOfPrints;
        this.name=name;
    }

    @Override
    public void run() {
        for(int counter=0;counter<numOfPrints;counter++)
        {
            try {
            // System.out.println(">>"+name+"<< "+cb.await());
            cb.await();
            System.out.println("["+name+"] "+startCounter);
            cb.await();
            //System.out.println("<<"+name+">> "+cb.await());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        startCounter+=3;
        }
    }

}

output

[Three] 3
[One] 1
[Two] 2
[One] 4
[Two] 5
[Three] 6
[Two] 8
[One] 7
[Three] 9
[One] 10
[Two] 11
[Three] 12
[Two] 14
[One] 13
[Three] 15
[One] 16
[Two] 17
[Three] 18
[Two] 20
[One] 19
[Three] 21
[One] 22
[Two] 23
[Three] 24
[Two] 26
[One] 25
[Three] 27
[One] 28
[Two] 29
[Three] 30

Can anyone help me with correct ans ?

Similar Ques Thread Synchronization - Synchronizing three threads to print 012012012012..... not working


Solution

  • As the others already mentioned, CyclicBarrier is not exactly the best tool for the task.

    I also share the opinion that the solution is to chain the threads and let always one thread set the go for the next one.

    Here goes an implementation using Semaphore:

    import java.util.concurrent.BrokenBarrierException; 
    import java.util.concurrent.Semaphore;
    
    public class PrintNumbersWithSemaphore implements Runnable {
    
    private final Semaphore previous;
    
    private final Semaphore next;
    
    private final int[] numbers;
    
    public PrintNumbersWithSemaphore(Semaphore previous, Semaphore next, int[] numbers) {
        this.previous = previous;
        this.next = next;
        this.numbers = numbers;
    }
    
    @Override
    public void run() {
    
        for (int i = 0; i < numbers.length; i++) {
            wait4Green();
    
            System.out.println(numbers[i]);
    
            switchGreen4Next();
        }
    }
    
    private void switchGreen4Next() {
            next.release();
    }
    
    private void wait4Green() {
        try {
            previous.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    
    static public void main(String argv[]) throws InterruptedException, BrokenBarrierException {
        Semaphore sem1 = new Semaphore(1);
        Semaphore sem2 = new Semaphore(1);
        Semaphore sem3 = new Semaphore(1);
        sem1.acquire();
        sem2.acquire();
        sem3.acquire();
        Thread t1 = new Thread(new PrintNumbersWithSemaphore(sem3, sem1, new int[] { 1, 4, 7 }));
        Thread t2 = new Thread(new PrintNumbersWithSemaphore(sem1, sem2, new int[] { 2, 5, 8 }));
        Thread t3 = new Thread(new PrintNumbersWithSemaphore(sem2, sem3, new int[] { 3, 6, 9 }));
        t1.start();
        t2.start();
        t3.start();
        sem3.release();
    
        t1.join();
        t2.join();
        t3.join();
    }
    
    }
    

    Here goes another one, in my opinion quite cumbersome implementation using CyclicBarrier:

    import java.util.concurrent.BrokenBarrierException; 
    import java.util.concurrent.CyclicBarrier;
    
    public class PrintNumbersWithCyclicBarrier implements Runnable {
    
    private final CyclicBarrier previous;
    
    private final CyclicBarrier next;
    
    private final int[] numbers;
    
    public PrintNumbersWithCyclicBarrier(CyclicBarrier previous, CyclicBarrier next, int[] numbers) {
        this.previous = previous;
        this.next = next;
        this.numbers = numbers;
    }
    
    @Override
    public void run() {
    
        for (int i = 0; i < numbers.length; i++) {
            wait4Green();
    
            System.out.println(numbers[i]);
    
            switchRed4Myself();
    
            switchGreen4Next();
        }
    }
    
    private void switchGreen4Next() {
        try {
            next.await();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    
    private void switchRed4Myself() {
        previous.reset();
    }
    
    private void wait4Green() {
        try {
            previous.await();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    
    static public void main(String argv[]) throws InterruptedException, BrokenBarrierException {
        CyclicBarrier cb1 = new CyclicBarrier(2);
        CyclicBarrier cb2 = new CyclicBarrier(2);
        CyclicBarrier cb3 = new CyclicBarrier(2);
        Thread t1 = new Thread(new PrintNumbersWithCyclicBarrier(cb3, cb1, new int[] { 1, 4, 7 }));
        Thread t2 = new Thread(new PrintNumbersWithCyclicBarrier(cb1, cb2, new int[] { 2, 5, 8 }));
        Thread t3 = new Thread(new PrintNumbersWithCyclicBarrier(cb2, cb3, new int[] { 3, 6, 9 }));
        t1.start();
        t2.start();
        t3.start();
        cb3.await();
    
        t1.join();
        t2.join();
        t3.join();
    }
    
    }