简体   繁体   English

wait / notify和wait / interrupt有什么区别?

[英]What is the difference between wait/notify and wait/interrupt?

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. 看来这个线程在其他线程调用此线程上的interrupt()notify()时都会唤醒。 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. 但是这两者都导致了相同的结果,也就是说,这个线程被唤醒了,所以我想问的是这两种情况的后果是如何相互不同的。

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. 当一个线程在某个监视器上调用notify时,它会唤醒正在该监视器上等待的单个线程,但是哪个线程被唤醒由调度程序决定。 (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. (或者一个线程可以调用notifyAll,它唤醒等待该监视器的所有线程,然后它们都争用监视器,然后输入回到等待。)这就是为什么呼叫的目标不同,通知是到监视器,它告诉调度程序选择一个线程来唤醒。

Unlike notify, interruption targets a specific thread. 与notify不同,中断针对特定线程。 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. 对于要在监视器上调用wait的线程,它必须首先获取该监视器,然后等待监视的释放,直到线程完成等待或被中断。

Oracle's recommendation is to use interruption only for cancellation. Oracle的建议是仅将中断用于取消。 Also the classes in java.util.concurrent are designed to use interrupt for cancellation. 此外,java.util.concurrent中的类设计为使用中断进行取消。

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. 在你的例子中,中断不会非常有效,因为控制不会离开while循环,线程仍然必须检查它正在等待的条件,并且没有检查while循环条件是否设置了中断标志。 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): 为了使这个代码在被中断后退出,而不是返回等待,将中断标志状态的检查添加到循环条件,并让catch块设置中断标志(当抛出异常时它会被重置):

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

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() . 正如人们已经指出的那样,唤醒线程不是唯一的结果,但是从线程t2t1调用t1.interrupt()将导致线程t1中的InterruptedException ,这是Object.notify()Thread.interrupt()之间的一个很大的区别Thread.interrupt()

You should understand that its method Object.wait() which throws checked InterruptedException and forces you to handle it. 您应该了解它的方法Object.wait()抛出已检查的InterruptedException并强制您处理它。 Object.wait . Object.wait

InterruptedException - if any thread interrupted the current thread before or while the current thread was waiting for a notification. InterruptedException - 如果任何线程在当前线程等待通知之前或当前线程中断当前线程。 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没有提供任何预先取消线程的机制,因此您必须为此目的使用中断机制(显然,如果您需要这样做。如果不适用于此,您可能会忽略此异常案件)。

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. InterruptedException之后,Java不会限制您的操作,您可以执行任何您想要的操作,但不建议将其用于实现线程取消策略之外的其他操作。 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. BlockingQueue.put(..)这样的API方法试图通过抛出InterruptedException来告诉你的是,即使它的阻塞操作也可以被抢先终止。 Its not necessary that all blocking API methods will provide you that facility. 并非所有阻塞API方法都能为您提供这种功能。

Cancellation/Termination of a thread using Thread.interrupt() is not a forceful but cooperative mechanism and is just a request not an order. 使用Thread.interrupt()取消/终止线程不是一个强有力但合作的机制,而只是一个请求而不是一个订单。

Your use of e.printStackTrace(); 您使用e.printStackTrace(); is strongly discouraged since this is usually not an error, if intention is to log it as an error. 强烈建议不要这样做,因为这通常不是错误,如果打算将其记录为错误。

Hope it helps !! 希望能帮助到你 !!

  1. Wait method is used to suspend a current thread on an object. Wait方法用于挂起对象上的当前线程。 Wait method is not from thread class but from java.lang.Object Wait方法不是来自线程类,而是来自java.lang.Object

  2. Notify method is used to wake the thread waiting on the object. Notify方法用于唤醒等待对象的线程。 Notify method is not from thread class but from java.lang.Object. Notify方法不是来自线程类,而是来自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 ie (Thread 1) is busy using it unless the work is done acquires a lock on telephone Object now B ie(Thread 2) tries to use Telephone but as A has acquired lock on it B it goes into wait state until lock is released. 假设例如一个人正在使用电话而B人也想使用电话但是作为一个人即(线程1)正在忙着使用它,除非工作完成后获得电话上的锁定现在B即(线程2)试图使用电话,但是当A已获得锁定时,它进入等待状态直到锁定被释放。

  • If Telephone object calls wait method it will restrict current thread which want to use Telephone and it will go into wait state. 如果Telephone对象调用wait方法,它将限制想要使用Telephone的当前线程,它将进入等待状态。
  • 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. 如果Person A(线程1)正在使用Telephone对象并且在某个任务中但是调用了中断方法,那么A将被发信号通知当前任务停止并且可能需要分配一些其他任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM