0

Is it true that notify works only after thread is finished? In code below I can't get notification until I comment while (true). How to tell main thread that part of thread job is done?

public class ThreadMain {
    public Thread reader;
    private class SerialReader implements Runnable {
        public void run() {
            while (true) {
                try {
                    Thread.sleep(3000);                
                    synchronized(this) {
                        System.out.println("notifying");
                        notify();
                        System.out.println("notifying done");
                    }                
                } catch (Exception e) {
                    System.out.println(e);
                }                
            }
        }
    }

    ThreadMain() {
        reader = new Thread(new SerialReader());
    }

    public static void main(String [] args) {
        ThreadMain d= new ThreadMain();    
        d.reader.start();
        synchronized(d.reader) {
            try {    
                d.reader.wait();
                System.out.println("got notify");
            } catch (Exception e) { 
                System.out.println(e);
            }    
        }        
    }
}
Vincent van der Weele
  • 12,927
  • 1
  • 33
  • 61
vico
  • 17,051
  • 45
  • 159
  • 315
  • Register and notify listeners. – Sotirios Delimanolis Jul 31 '13 at 15:09
  • [This might be worth reading](http://stackoverflow.com/questions/6916398/communicating-between-two-threads). – Shaz Jul 31 '13 at 15:12
  • 3
    Please note that you are calling notify on the instance of class SerialReader, not the instance of class Thread. Thus d.reader.wait() waits on another object's monitor than you use in the worker. – oddparity Jul 31 '13 at 15:16

3 Answers3

1

You should try to avoid using wait and notify with the newer versions of Java, as they're difficult to get right. Try using something like a BlockingQueue instead

public class ThreadMain {
    public final BlockingQueue<Boolean> queue = new LinkedBlockingQueue<>();
    private class SerialReader implements Runnable {
        public void run() {
            while (true) {
                try {
                    Thread.sleep(3000);                
                    System.out.println("notifying");
                    queue.offer(Boolean.TRUE);
                    System.out.println("notifying done");            
                } catch (Exception e) {
                    System.out.println(e);
                }                
            }
        }
    }

    ThreadMain() {
        reader = new Thread(new SerialReader());
    }

    public static void main(String [] args) {
        ThreadMain d= new ThreadMain();    
        d.reader.start();
        try {    
            d.queue.take(); // block until something is put in the queue
            System.out.println("got notify");
        } catch (Exception e) { 
            System.out.println(e);
        }          
    }
}
Zim-Zam O'Pootertoot
  • 17,888
  • 4
  • 41
  • 69
  • If one really want to use concurrency classes, a better fit would be CountDownLatch or Semaphore. But BlockingQueue could be nice for incremental notifications. – Ralf H Jul 31 '13 at 16:26
0

If you want to be notified when the Thread t completes, call t.join() in the calling Thread. This will block until t has finished its Runnable.

Ralf H
  • 1,392
  • 1
  • 9
  • 17
0

As user oddparity noted in the comments, you are calling wait() and notify() on different objects. A possible fix for this would be to make your SerialReader extend Thread rather than implement Runnable and then assigning reader to be a new instance of the SerialReader directly. :

public class ThreadMain {
    public Thread reader;
    private class SerialReader extends Thread {
        public void run() {
            while (true) {
                try {
                    Thread.sleep(3000);                
                    synchronized(this) {
                        System.out.println("notifying");
                        notify();
                        System.out.println("notifying done");
                    }                
                } catch (Exception e) {
                    System.out.println(e);
                }                
            }
        }
    }

    ThreadMain() {
        reader = new SerialReader();
    }

    public static void main(String [] args) {
        ThreadMain d= new ThreadMain();    
        d.reader.start();
        synchronized(d.reader) {
            try {    
                d.reader.wait();
                System.out.println("got notify");
            } catch (Exception e) { 
                System.out.println(e);
            }    
        }        
    }
}

If you want to use Runnable with wait()/notify() you can do it this way :

public class ThreadMain {

  public Thread reader;

  private class SerialReader implements Runnable {

    public void run() {
      Thread thisThread = Thread.currentThread();

      while (true) {
        try {
          Thread.sleep(3000);
          synchronized (thisThread) {
            System.out.println("notifying");
            thisThread.notify();
            System.out.println("notifying done");
          }
        } catch (Exception e) {
          System.out.println(e);
        }
      }
    }
  }

  ThreadMain() {
    reader = new Thread(new SerialReader());
  }

  public static void main(String[] args) {
    ThreadMain d = new ThreadMain();
    d.reader.start();
    synchronized (d.reader) {
      try {
        d.reader.wait();
        System.out.println("got notify");
      } catch (Exception e) {
        System.out.println(e);
      }
    }
  }
}
SamYonnou
  • 2,068
  • 1
  • 19
  • 23
  • …but instead of teaching the OP about extending Thread (which only diverts from more useful alternatives), we should point out that there are better patterns/classes in [java.util.concurrent](http://docs.oracle.com/javase/tutorial/essential/concurrency/) than `wait/notify`. – Ralf H Jul 31 '13 at 15:59
  • For some reason it is mor convenient to me is to have Runnable. Is it possible somehow to have thread handle from runnable and using it to make Synchronized? – vico Aug 01 '13 at 05:49
  • I must use java 1.4, so there is no possibility of using java.util.concurrent – vico Aug 01 '13 at 05:51
  • in that case, using Thread#join is most appropriate. Not sure why anybody would still use Java 1.4, though. – Ralf H Aug 01 '13 at 09:33
  • You can do it with `Runnable` if you really want to. See edit. – SamYonnou Aug 01 '13 at 13:13