Search code examples
javamultithreadingconcurrencywaitthread-synchronization

Why does it matter what object I use wait()/notify() on, if I just want a way to signal between threads?


So I have a classic case of "my code works, but I dont know why".

I'm have a program that creates a thread, and when I receive a certain input from scanner, I pass control of the string to a worker thread. To do this, I make my thread wait(), and when I get the correct input from my UI thread, I notify().

Here is my code. For simplicity, I've just used one thread.

package main;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;


class ThreadDemo extends Thread {
       private Thread t;
       private String threadName;
       volatile Boolean keepRunning = true;
       private Queue<String> q = new LinkedList<String>();


       ThreadDemo( String name){
           threadName = name;
           System.out.println("Creating " +  threadName );
       }

       public void in(String ex){
           q.add(ex);
           System.out.println("Added " + ex + "to queue of " + threadName);
           synchronized(t){
               t.notify();
           }       
       }


       public void run() {
           System.out.println("Starting to loop.");
            while (keepRunning) {
                try {
                    //Why does it matter that I synchronized t? 
                    synchronized(t){
                        System.out.println(threadName +  "Waiting");
                        t.wait();
                    }
                } catch (InterruptedException e) {
                    System.out.println("Thread interrupted " + e.toString());
                    }
                System.out.println(threadName +  "notified");
                if (q.size()>0){
                    String out = q.remove();
                    System.out.println(threadName + "received " + out);
                }
            }
            System.out.println("Done looping.");
       }

       public void start ()
       {
          System.out.println("Starting " +  threadName );
          if (t == null)
          {
             t = new Thread (this, threadName);
             t.start ();
          }
       }
    }


public class DataAnalysisProgram {

    public static void main(String[] args) {
          ThreadDemo T1 = new ThreadDemo( "Thread-1");
          T1.start();

          System.out.println("say something");
          Scanner s = new Scanner(System.in);
          String t;
          do{
              t = s.next();
              T1.in(t);
          }while (!t.equals("stop"));

          T1.keepRunning = false;
          T1.interrupt();
          s.close();
    }
} 

So this works fine. My thread waits until I use notify. However, I dont really understand the significance of which object I call notify and wait on.

In my implementation, I willy nilly did t.wait()/t.notify(), where t is my thread object. I suppose it would still work if I did threadName.wait()/threadName.notify(). Why do we call notify and wait on seemingly arbitrary objects? I know I'm missing a concept here about notify and wait.


Solution

  • In fact, you broke the contract when you invoked wait on a Thread instance:

    It is recommended that applications not use wait, notify, or notifyAll on Thread instances.

    This is because Thread uses that for its own internal purposes.

    To answer your question: the Thread object is not a thread. Saying t.notify() does not notify t, it notifies a thread waiting on t's monitor. In this context an instance of Thread is just another Java object, and all Java objects have a monitor associated with them.

    Your suggestion to use the monitor of String threadName is another bad idea because you don't control the lifecycle of string instances and may easily trample upon issues with interned strings.

    It is recommended practice not to involve arbitrary object's monitors in thread coordination, but prefer to use dedicated instances of Object for that. This is motivated by the general advantages of the principle of the separation of concerns.