0

How can I notify Thread t1 and Thread t2 at the same time (so it is the same probability to get hey 1 as hey2 first)? I've tried notifyAll, but couldn't make it work.

class Thr extends Thread
{
    Thr () throws InterruptedException
    {
        Thread t1 = new Thread() {
            public synchronized void run()
            {
                while (true)
                {
                    try {
                        wait();
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    try
                    {
                        Thread.sleep(1500);
                    } catch (Exception e) { }
                    System.out.println("hey 1");
                }
            }
        };

        Thread t2 = new Thread() {
            public synchronized void run()
            {
                while (true)
                {                    
                    try {
                        wait();
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    try
                    {
                        Thread.sleep(1500);
                    } catch (Exception e) { }
                    System.out.println("hey 2");
                }
            }
        };

        t1.start();
        t2.start();
    }

    public static void main(String args[]) throws InterruptedException
    {
        new Thr();
    }
}
good_evening
  • 21,085
  • 65
  • 193
  • 298
  • 1
    I cannot see any `notify` nor `notifyAll` in the code you posted. – Jagger Nov 11 '12 at 00:19
  • I've tried it in constructor after t2.start();, I also tried in thread t2 calling t1.notify(); but nothing worked. I just didn't post as it hadn't work. – good_evening Nov 11 '12 at 00:20

4 Answers4

2

You should wait on a shared object and use notifyAll as in:

class Thr extends Thread
{
    Thr () throws InterruptedException
    {
        final Object lock = new Object ();

        Thread t1 = new Thread() {
            public void run()
            {
                    try {
                        synchronized (lock) {
                            lock.wait();
                        }
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }

                    System.out.println("hey 1");
            }
        };

        Thread t2 = new Thread() {
            public synchronized void run()
            {
                    try {
                        synchronized (lock) {
                            lock.wait();
                        }
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }

                    System.out.println("hey 2");
            }
        };

        t1.start();
        t2.start();
        synchronized (lock) {
            lock.notifyAll ();
        }
    }

    public static void main(String args[]) throws InterruptedException
    {
        new Thr();
    }
}
ShyJ
  • 4,560
  • 1
  • 19
  • 19
  • Indeed. The problem is that by declaring the `run` method to be `synchronized` and calling `wait()` (which is really `this.wait()`), each thread is waiting on itself. A shared lock object is exactly what's needed. However, there's a race condition in this code: the `lock.notifyAll()` statement might be executed before either of the `lock.wait()` statements in `t1` and `t2`. Also, there's no need for the `run` methods to be declared `synchronized`. – Ted Hopp Nov 11 '12 at 00:32
  • This will cause a race condition. If the starter thread calls `notifyAll` before the started threads have called `wait`, then this code will fail. – Brian Nov 11 '12 at 00:33
  • @Brian: I just use Thread.sleep(2000); before notifying all. But it still gives me hey 1 first most of the times. – good_evening Nov 11 '12 at 00:35
  • That's horrible practice in concurrency and you really should avoid it. You should never have to call `Thread.sleep`, there's always a better solution. As for it giving you one before the other more often, it's probably because the scheduler is giving the lock to the first thread since it was the first one that waited on the object. – Brian Nov 11 '12 at 00:37
  • @hey - I don't know how you're sleeping, but I suggest removing the `sleep` calls from the threads and instead put the `notifyAll` in a loop that also sleeps. The problem with sleeping in the threads is that once one thread gets to go first, it most likely gets to start its sleep cycle first, goes into wait mode first, etc. – Ted Hopp Nov 11 '12 at 00:40
1

The right way to do this is to use notifyAll. The real problem with your code seems to be that you have two threads waiting for notifications on different mutexes. You need them to wait on a single object ... as described in @ShyJ's answer.


Note that there is NO WAY that you can code this so that the notification is guaranteed to be delivered first to either thread with equal probability:

  • The Java threading specs make no guarantees of fairness in wait / notify.

  • The thread scheduler implemented (typically) at the OS-level (typically) makes no such guarantees either.

The point is that the application has no control over this. The best approach is to just let wait/notifyAll do what they normally do, and design your application so that any bias in the thread scheduling does not affect the application's behaviour in an important way.

(FWIW, the usual problem is that people explicitly or implicitly assume non-randomness ... and get burned when threads get scheduled in an unexpectedly random order.)

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
0

I highly recommend avoiding the use of wait/notify and use something more robust. The problem is that using wait/notify in any combination will likely result in a race condition.

The only way to give equal probability to them academically is to create two Semaphore objects, have the threads try to acquire them, and use Random to choose which one to release first. Even then, if the scheduler decides to run the first one that tried to obtain the lock, then you get bias there anyway, regardless of whether or not the Sempahore is fair. This forces you to wait until the first thread is done before running the second, such as via Thread.join.

Bottom line, the only way to guarantee order in a concurrent system is to force them into a single-threaded format, which throws out the whole point of having them concurrent in the first place.

Brian
  • 17,079
  • 6
  • 43
  • 66
0

If you are using Java versions greater than 1.4, then it would greatly simplyfy your task by using any of the concurrent locks:

java.util.concurrent.locks specially the ReadWrite type.

For now for message passing to all the threads at the same type - implement Observer Pattern

rock_win
  • 755
  • 1
  • 5
  • 14