Why does it matter which object I use wait () / notify () if I just want to signal between threads?

So, I have a classic case "my code works, but I don't know why".

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

Here is my code. For the sake of 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 great. My thread is waiting until I notify about it. However, I don't really understand the meaning of that object I am calling notify

and wait

on.

In my implementation, I willy nilly did t.wait()/t.notify()

where t is my thread object. I guess it doesn't matter if I did threadName.wait()/threadName.notify()

. Why are we calling notification and waiting on seemingly arbitrary objects? I know I am missing the concept of notification and waiting.

+3


source to share


2 answers


You actually broke the contract when you called wait

on the instance Thread

:

It is recommended that applications are not used wait

, notify

or notifyAll

in Thread

instances.

This is due to the fact that he Thread

uses it for his own internal purposes.



To answer your question: an object is Thread

not a thread. The statement t.notify()

does not notify t

, it notifies a thread waiting to be monitored t

. In this context, an instance Thread

is just another Java object, and all Java objects have a monitor associated with them.

Your suggestion to use a monitor String threadName

is another bad idea, because you have no control over the lifecycle of string instances and can easily trample issues with interned strings.

It is recommended not to include arbitrary object monitors in thread coordination, but prefers to use special instances for this Object

. This is motivated by the general benefits of the separation of concerns principle.

+5


source


Why are we calling notification and waiting on seemingly arbitrary objects?

Calling waiting and notifying do not directly affect the object itself, so it is indeed arbitrary. All you need is some object that you can use as a connection point.

In fact, the historical assumption has been made in Java that it is possible to use wait and notify on arbitrary objects, since locking control adds little cost and complexity to all objects, although the mechanism is not used for the vast majority of objects. Instead, they had to use a dedicated Lock class, or have objects that implement a specific interface to indicate that you can call them wait / notify or something similar.



In any case, it is a good idea not to use arbitrary objects, because (a) it is confusing, and (b) it risks getting confused with other code that might be trying to use the same object. If there is no sapient object, you must create one for this purpose:

    private final Object lock = new Object();

      

+1


source







All Articles