What is the difference between wait/notify and wai

2020-03-01 16:32发布

问题:

synchronized (Foo.class) {
    while (someCondition) {
        try {
            Foo.class.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();            
        }
    }
}

It seems that this thread both wakes when some other thread call interrupt() or notify() on this thread. Are there any differences between the two?

--EDIT--

I know one is for notifying an object, the other interrupts a thread. But both of these lead to the same consequence, that is, this thread is waken up, so what I want to ask is how these 2 situations' consequences are different from each other.

回答1:

When a thread calls notify on some monitor, it wakes up a single thread that's waiting on that monitor, but which thread gets woken is decided by the scheduler. (Alternatively a thread can call notifyAll, which wakes up all the threads waiting for that monitor, then they all contend for the monitor, then the losers go back to waiting.) That's why the target of the call is different, the notification is made to the monitor, which tells the scheduler to pick a thread to wake up.

Unlike notify, interruption targets a specific thread. And interruption does not require that the interrupted thread be waiting on a monitor. For a thread to call wait on a monitor it has to have acquired that monitor first, then wait releases that monitor until the thread is done waiting or is interrupted.

Oracle's recommendation is to use interruption only for cancellation. Also the classes in java.util.concurrent are designed to use interrupt for cancellation.

In your example interruption won't be very effective, because control doesn't leave the while loop, the thread still has to check the condition it's waiting on, and there's no check in the while loop condition for whether the interrupt flag is set. It's likely the thread that's interrupted will go right back to waiting.

In order to make this code quit once it's interrupted, rather then return to waiting, add a check for the interrupted flag status to the loop condition, and have the catch block set the interrupt flag (which gets reset when the exception is thrown):

synchronized (Foo.class) {
    while (someCondition && !Thread.currentThread().isInterrupted()) {
        try {
            Foo.class.wait();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();            
        }
    }
}


回答2:

Basically, you are not looking for a text book difference but difference in their uses cases.

As folks have already pointed out, waking up the thread is not the only consequence but calling t1.interrupt() from Thread t2 for t1 will cause an InterruptedException in thread t1 and that is a big difference between Object.notify() and Thread.interrupt().

You should understand that its method Object.wait() which throws checked InterruptedException and forces you to handle it. Object.wait.

InterruptedException - if any thread interrupted the current thread before or while the current thread was waiting for a notification. The interrupted status of the current thread is cleared when this exception is thrown.

Then you should consult this question to get an idea about handling this exception.

Difference between the two lies in the fact that one is for inter thread communication for usual logical programing stuff ( wait & notify ) and other one ( interrupt) is for preemptive thread cancellation / termination even in cases of blocking operations. You have to note that Java doesn't provide any mechanism to preemptively cancel a thread so you have to use interrupt mechanism for that purpose ( Obviously, if that is needed in your case. You might very well ignore this Exception if not applicable in your case).

Java doesn't restrict your actions after InterruptedException and you can do anything you want but using it for things other than implementing Thread Cancellation Policy is not advised. Thread Cancellation Policy is often ignored and less discussed area when programmers write multi threaded programs and that is why you might be finding it difficult to understand the use case.

What does an API method like BlockingQueue.put(..) is trying to tell you by throwing InterruptedException is that even its blocking operation can be preemptively terminated. Its not necessary that all blocking API methods will provide you that facility.

Cancellation/Termination of a thread using Thread.interrupt() is not a forceful but cooperative mechanism and is just a request not an order.

Your use of e.printStackTrace(); is strongly discouraged since this is usually not an error, if intention is to log it as an error.

Hope it helps !!



回答3:

  1. Wait method is used to suspend a current thread on an object. Wait method is not from thread class but from java.lang.Object

  2. Notify method is used to wake the thread waiting on the object. Notify method is not from thread class but from java.lang.Object.

  3. Interrupt method is used to to indicate the current thread that is should stop current job execution and can start other job. Interrupt method is from thread class.

Let see the real life example:

Consider Telephone as Object , Person as Thread. Suppose for instance A person is using Telephone and B person also wants to use the telephone but as A person i.e (Thread 1) is busy using it unless the work is done acquires a lock on telephone Object now B i.e(Thread 2) tries to use Telephone but as A has acquired lock on it B it goes into wait state until lock is released.

  • If Telephone object calls wait method it will restrict current thread which want to use Telephone and it will go into wait state.
  • If Telephone object calls notify it will signal the thread waiting on it to acquire lock and proceed with the intended work.
  • If Person A(Thread 1) is using Telephone object and is in some task but interrupt method is called then A will be signaled to stop with current task and may need to do some other task assigned.