Anand Patel
Anand Patel

Reputation: 6421

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

I am trying to synchronize three threads to print 012012012012.... but it is not working correctly. Each thread is assigned a number which it prints when it receives a signal from main thread. There is something wrong with the following program which I am not able to catch.

public class Application {
    public static void main(String[] args) {

        int totalThreads = 3;
        Thread[] threads = new Thread[totalThreads];

        for (int i = 0; i < threads.length; i++) {
            threads[i] = new MyThread(i);
            threads[i].start();
        }

        int threadIndex = 0;
        while (true) {
            synchronized(threads[threadIndex]) {
                threads[threadIndex].notify();
            }

            threadIndex++;
            if (threadIndex == totalThreads) {
                threadIndex = 0;
            }
        }
    }
}

class MyThread extends Thread {
    private int i;

    public MyThread(int i) {
        this.i = i;
    }

    @Override
    public void run() {
        while (true) {
            synchronized(this) {
                waitForSignal();
                System.out.println(i);
            }
        }
    }

    private void waitForSignal() {
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Upvotes: 2

Views: 630

Answers (4)

Himanshu Verma
Himanshu Verma

Reputation: 53

package threads;

import java.util.concurrent.Semaphore;

public class ZeroEvenOddPrinter {
   class Runner extends Thread{
       Semaphore prev;
       Semaphore next;
       int num = 0;
       public Runner(Semaphore prev,Semaphore next,int num){
           this.prev = prev;
           this.next = next;
           this.num = num;
       }
       @Override
       public void run(){
            while (true) {
                try {
                    Thread.sleep(100);
                    prev.acquire();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                if (num == 0)
                    System.out.println(0);
                else {
                    System.out.println(num);
                    num = num + 2;
                }
                next.release();
            }
        }
   }
   static public void main(String args[]) throws InterruptedException{
       Semaphore sem1 = new Semaphore(1);
       Semaphore sem2 = new Semaphore(1);
       Semaphore sem3 = new Semaphore(1);
       ZeroEvenOddPrinter zeo = new ZeroEvenOddPrinter();
       Runner t1 = zeo.new Runner(sem1,sem2,0);
       Runner t2 = zeo.new Runner(sem2,sem3,1);
       Runner t3 = zeo.new Runner(sem3,sem1,2);
       sem1.acquire();
       sem2.acquire();
       sem3.acquire();
       t1.start();
       t2.start();
       t3.start();
       sem1.release();
   }
}

Here i am using semaphores as triggers for all the three threads. Initially all threads will be blocked on sem1,sem2,sem3. Then i will release the sem1 and first thread will execute then it will release the second thread and so on... The best part is you extend this logic to n number of threads. Good Luck!!!

Upvotes: 0

Marco13
Marco13

Reputation: 54639

Another possible solution: In the main thread, you can wait immediately after having notified a thread (in the same synchronized block), like this:

synchronized (threads[threadIndex])
{
    threads[threadIndex].notify();
    threads[threadIndex].wait(); // try/catch here
}

And in the run method of the thread, you can use notifyAll to wake up the main thread after the thread finished its work:

synchronized (this)
{
    waitForSignal();
    System.out.println(i);
    notifyAll();
}

More sophisticated solutions would involve classes from the java.util.concurrent.locks package.

Upvotes: 0

JensG
JensG

Reputation: 13411

Here's your problem:

    int threadIndex = 0;
    while (true) {
        synchronized(threads[threadIndex]) {
            threads[threadIndex].notify();
        }

        threadIndex++;
        if (threadIndex == totalThreads) {
            threadIndex = 0;
        }
    }

The main thread notifies all threads in the right order. However, your threads are working independently. They may or may not get scheduled at a specific point in time. So the end result may be, that thread 2 is reaching the wait/print lock before thread 1 before thread 0. The final order is not determined by you sending the notifications, but (in essence) by the scheduler.

The solution is to change it this way:

  1. the main thread notifies exactly one thread: thread 0
  2. every thread does his work and when done, notifies the next thread in line
  3. obviously the last thread has to notify thread 0 again.

Upvotes: 0

jtahlborn
jtahlborn

Reputation: 53694

You need more coordination. the notify call does not immediately wake up the thread and force it to proceed. Instead, think of notify as sending an email to the thread to let it know that it can proceed. Imagine if you wanted your 3 friends to call you in order. You sent friend 1 an email to call you, waited one second, sent an email to friend 2, waited a second, and sent an email to friend 3. do you think you'd get called in that exact order?

one way to add more coordination would be to have some shared state which indicates whose turn it is. if all your friends could see your house, you could put a number on the outside of the house indicating whose turn it was to call. each friend would wait until they saw their number, and then call.

Upvotes: 3

Related Questions