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

时间:2015-05-27 00:39:20

标签: java multithreading wait notify interruption

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

当这个线程上的某个其他线程调用interrupt()notify()时,这个线程似乎都会唤醒。这两者之间有什么不同吗?

- 编辑 -

我知道一个用于通知一个对象,另一个用于中断一个线程。但是这两者都导致了相同的结果,也就是说,这个线程被唤醒了,所以我想问的是这两种情况是怎样的。后果各不相同。

3 个答案:

答案 0 :(得分:3)

当线程在某个监视器上调用notify时,它会唤醒在该监视器上等待的单个线程,但哪个线程被唤醒由调度程序决定。 (或者一个线程可以调用notifyAll,唤醒等待该监视器的所有线程,然后它们都争用监视器,然后输入回到等待。)这就是呼叫目标不同的原因,通知发送到监视器,告诉调度程序选择要唤醒的线程。

与notify不同,中断以特定线程为目标。并且中断不要求被中断的线程在监视器上等待。对于要在监视器上调用wait的线程,它必须首先获取该监视器,然后等待监视的释放,直到线程完成等待或被中断。

Oracle的建议是仅使用中断进行取消。此外,java.util.concurrent中的类设计为使用中断进行取消。

在你的例子中,中断不会非常有效,因为控制不会离开while循环,线程仍然必须检查它等待的条件,以及那里的中断没有检查while循环条件是否设置了中断标志。被中断的线程可能会立即回到等待状态。

为了使该代码在被中断后退出,而不是返回等待,将中断标志状态的检查添加到循环条件,并使catch块设置中断标志(重置当抛出异常时):

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

答案 1 :(得分:1)

基本上,您不是在寻找教科书差异,而是在使用案例上有所不同。

正如大家已经指出的那样,唤醒线程并不是唯一的结果,但是从t1.interrupt()的线程t2调用t1将导致线程t1中出现InterruptedException这是Object.notify()Thread.interrupt()之间的巨大差异。

你应该理解它的方法Object.wait()会抛出已检查InterruptedException并迫使你处理它。 Object.wait

  

InterruptedException - 如果有任何线程中断了当前线程   在当前线程等待通知之前或期间。该   此时清除当前线程的中断状态   抛出异常。

然后您应该咨询this question以了解处理此异常的想法。

两者之间的区别在于,一个用于通常逻辑编程内容(等待和通知)的线程间通信,而另一个(中断)用于抢占线程取消/终止,即使在阻塞操作的情况下也是如此。您必须注意,Java没有提供任何预先取消线程的机制,因此您必须为此目的使用中断机制(显然,如果您需要这样做。如果不适用,您可能会很好地忽略此异常在你的情况下)。

Java不会在InterruptedException之后限制您的操作,您可以执行任何您想要的操作,但不建议将其用于实现线程取消策略之外的其他操作。当程序员编写多线程程序时,线程取消策略经常被忽略,讨论较少,这就是为什么你可能会发现很难理解用例的原因。

BlockingQueue.put(..)这样的API方法试图通过抛出InterruptedException告诉你的是,即使它的阻塞操作也可以被抢先终止。并非所有阻塞API方法都能为您提供这种功能。

取消/使用Thread.interrupt()终止线程并不是一种强有力但合作的机制,而只是一个请求而非订单。

强烈建议不要使用e.printStackTrace();,因为这通常不是错误,如果打算将其记录为错误。

希望它有所帮助!!

答案 2 :(得分:0)

  1. Wait方法用于挂起对象上的当前线程。 Wait方法不是来自线程类,而是来自java.lang.Object

  2. Notify方法用于唤醒等待对象的线程。 Notify方法不是来自线程类,而是来自java.lang.Object。

  3. 中断方法用于指示当前线程 应该停止当前的工作执行,并可以开始其他工作。 中断方法来自线程类。

  4. 让我们看看现实生活中的例子:

    将电话视为对象,将人视为线程。 假设例如一个人正在使用电话而B人也想使用电话但是作为一个人即(线程1)正在忙着使用它,除非工作完成后获得电话上的锁定现在B即(线程2)试图使用电话,但是当A已获得锁定时,它进入等待状态直到锁定被释放。

    • 如果Telephone对象调用wait方法,它将限制当前线程 想要使用电话,它将进入等待状态。
    • 如果电话对象呼叫通知,它将通知线程等待 它获取锁定并继续进行预期的工作。
    • 如果Person A(线程1)正在使用Telephone对象并且处于某项任务中 但是中断方法被调用然后A将被发信号通知停止 当前任务,可能需要分配一些其他任务。