-3


I have three threads ThreadA, ThreadB and ThreadC printing values A, B and C respectively in loop.
I want output to be like A,B,C and then again A, B and C till loops are executing in threads.I want to write this sample program using wait and notify. Below code is printing the desired output but sometimes I am just seeing "A" in output, I am not able to figure out the case.

public class ThreadOrder {

    public static void main(String[] args) {
        Object lockAB = new Object();
        Object lockBC = new Object();
        Object lockCA = new Object();

        Thread threadA = new Thread(new ThreadOrder().new ThreadA(lockAB, lockCA));
        Thread threadB = new Thread(new ThreadOrder().new ThreadB(lockAB, lockBC));
        Thread threadC = new Thread(new ThreadOrder().new ThreadC(lockBC, lockCA));

        threadA.start();
        threadB.start();
        threadC.start();
    }

    class ThreadA implements Runnable {
        Object lockAB;
        Object lockCA;

        public ThreadA(Object lockAB, Object lockCA) {
            this.lockAB = lockAB;
            this.lockCA = lockCA;
        }

        @Override
        public void run() {
            for(int i=0; i<3; i++) {
                if(i!=0) {
                    try {
                        synchronized (lockCA) {
                            lockCA.wait();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("A");
                synchronized (lockAB) {
                    lockAB.notify();
                }
            }
        }

    }

    class ThreadB implements Runnable {
        Object lockAB;
        Object lockBC;

        public ThreadB(Object lockAB, Object lockBC) {
            this.lockAB = lockAB;
            this.lockBC = lockBC;
        }

        @Override
        public void run() {
            for(int i=0; i<3; i++) {
                try {
                    synchronized (lockAB) {
                        lockAB.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("B");
                synchronized (lockBC) {
                    lockBC.notify();
                }
            }
        }

    }

    class ThreadC implements Runnable {
        Object lockBC;
        Object lockCA;

        public ThreadC(Object lockBC, Object lockCA) {
            this.lockBC = lockBC;
            this.lockCA = lockCA;
        }

        @Override
        public void run() {
            for(int i=0; i<3; i++) {
                try {
                    synchronized (lockBC) {
                        lockBC.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("C");
                synchronized (lockCA) {
                    lockCA.notify();
                }
            }
        }

    }
}
the-dumb-programmer
  • 485
  • 3
  • 14
  • 27

4 Answers4

1

You call wait, but you haven't tested if there's anything to wait for. You call notify, but you haven't changed anything that you would need to notify another thread about. You have all these synchronized methods, but no shared state for the synchronization to protect.

Nothing in your code makes any sense and it seems that you fundamentally don't understand what the wait/notify mechanism does. The wait function allows a thread to wait for some shared state to change, and the notify function allows one thread to tell others that some shared state has changed. But there has to be some shared state because the wait/notify mechanism (unlike a lock or sempahore) is internally stateless.

You should probably have some shared state protected by the synchronization. It should encode which thread should go next. If you need to print, but the shared state says it's not your turn, then you have something to wait for. When you print and make it some other thread's turn to print next, then you have something to notify other threads about.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
0

Consider creating a ring of threads connected to one another by blocking queues. Then you can pass a token around the ring. Each thread waits to receive the token, prints its output, passes the token on to the next thread in the ring, and goes back to waiting.

Solomon Slow
  • 25,130
  • 5
  • 37
  • 57
0
package com.test.algorithms;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;

public class PrintInOrder {

    private static Integer[] a = { 1, 1, 1 };
    private static Integer[] b = { 2, 2, 2 };
    private static Integer[] c = { 3, 3, 3 };
    private static Integer[] d = { 4, 4, 4 };

    public static void main(String[] args) throws InterruptedException {

        QueueOrder q1 = null;
        QueueOrder q2 = null;
        QueueOrder q3 = null;
        QueueOrder q4 = null;

        q1 = new QueueOrder(a);
        q2 = new QueueOrder(b);
        q3 = new QueueOrder(c);
        q4 = new QueueOrder(d);

        q1.setChild(q2);

        q2.setChild(q3);

        q3.setChild(q4);

        q4.setChild(q1);

        Thread t1 = new Thread(q1);
        Thread t2 = new Thread(q2);
        Thread t3 = new Thread(q3);
        Thread t4 = new Thread(q4);


        t1.start();
        t2.start();
        t3.start();
        t4.start();

        QueueOrder q = q1;

        while (!q.queue.isEmpty()) {

            synchronized (q) {
                if (!q.isPrinted) {
                    q.notify();
                    q.wait();
                }
            }
            q = q.child;
        }

        t1.join();
        t2.join();
        t3.join();
        t4.join();

    }

}

class QueueOrder implements Runnable {

    Integer[] arr;
    QueueOrder child;
    Queue<Integer> queue = new LinkedList<>();
    boolean isPrinted = false;

    QueueOrder(Integer[] arr) {
        this.arr = arr;
        queue.addAll(Arrays.asList(arr));
    }

    public QueueOrder getChild() {
        return child;
    }

    public void setChild(QueueOrder child) {
        this.child = child;
    }

    public void run() {

        while (!this.queue.isEmpty()) {

            synchronized (this) {
                if (!this.isPrinted) {
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                } 
            }

            System.out.print("**" + this.queue.poll());
            this.isPrinted = false;
            synchronized (this) {
                this.notify();
            }

        }
    }
}
0
package com.test.algorithms;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;

public class PrintInOrder1 {

    private static Integer[] a = { 1, 1, 1 };
    private static Integer[] b = { 2, 2, 2 };
    private static Integer[] c = { 3, 3, 3 };
    private static Integer[] d = { 4, 4, 4 };

    public static void main(String[] args) throws InterruptedException {

        QueueOrder1 q1 = null;
        QueueOrder1 q2 = null;
        QueueOrder1 q3 = null;
        QueueOrder1 q4 = null;

        q1 = new QueueOrder1(a);
        q2 = new QueueOrder1(b);
        q3 = new QueueOrder1(c);
        q4 = new QueueOrder1(d);

        q1.setChild(q2);
        q1.isPrinted = true;

        q2.setChild(q3);

        q3.setChild(q4);

        q4.setChild(q1);

        Thread t1 = new Thread(q1);
        Thread t2 = new Thread(q2);
        Thread t3 = new Thread(q3);
        Thread t4 = new Thread(q4);


        t1.start();
        t2.start();
        t3.start();
        t4.start();



        t1.join();
        t2.join();
        t3.join();
        t4.join();

    }

}

class QueueOrder1 implements Runnable {

    Integer[] arr;
    QueueOrder1 child;
    Queue<Integer> queue = new LinkedList<>();
    boolean isPrinted = false;

    QueueOrder1(Integer[] arr) {
        this.arr = arr;
        queue.addAll(Arrays.asList(arr));
    }

    public QueueOrder1 getChild() {
        return child;
    }

    public void setChild(QueueOrder1 child) {
        this.child = child;
    }

    public void run() {

        while (!this.queue.isEmpty()) {

            synchronized (this) {
                if (!this.isPrinted) {
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                } 
            }

            System.out.print("**" + this.queue.poll());
            this.isPrinted = false;
            synchronized (this.child) {
                if(!this.child.isPrinted) {
                    this.child.notify();
                }
            }

        }
    }
}