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.
In fact, you broke the contract when you invoked wait
on a Thread
instance:
It is recommended that applications not use
wait
,notify
, ornotifyAll
onThread
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.