【问题标题】:What is the difference between wait/notify and wait/interrupt?等待/通知和等待/中断有什么区别?
【发布时间】:2015-05-27 00:39:20
【问题描述】:
synchronized (Foo.class) {
    while (someCondition) {
        try {
            Foo.class.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();            
        }
    }
}

似乎当其他线程在此线程上调用interrupt() 或notify() 时,此线程都被唤醒。两者有什么区别吗?

--编辑--

我知道一个用于通知对象,另一个用于中断线程。但是这两个导致的结果是一样的,就是这个线程被唤醒了,所以我想问的是,这两种情况的结果有什么不同。

【问题讨论】:

  • 一个导致异常,另一个导致返回。一个通知一个对象,另一个中断一个线程。一个是苹果,另一个是橙子。
  • 醒来并不是唯一的后果,正如您将在文档中看到的那样。

标签: java multithreading wait notify interruption


【解决方案1】:

当一个线程在某个监视器上调用 notify 时,它会唤醒在该监视器上等待的单个线程,但 哪个线程被唤醒是由调度程序决定的。 (或者一个线程可以调用notifyAll,它唤醒所有等待该监视器的线程,然后它们都竞争监视器,然后失败者返回等待。)这就是为什么调用的目标不同,发出通知到监视器,它告诉调度程序选择一个线程来唤醒。

与通知不同,中断针对特定线程。并且中断不需要被中断的线程在监视器上等待。线程要在监视器上调用 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();            
        }
    }
}

【讨论】:

    【解决方案2】:

    基本上,您不是在寻找教科书上的差异,而是在他们的用例上的差异。

    正如人们已经指出的那样,唤醒线程并不是唯一的结果,而是从线程 t2 为 t1 调用 t1.interrupt() 会导致线程 t1 中出现 InterruptedException,这与 @ 之间存在很大差异987654328@ 和Thread.interrupt()。

    你应该明白它的方法Object.wait() 抛出检查InterruptedException 并强制你处理它。 Object.wait。

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

    那么您应该咨询this question 以了解如何处理此异常。

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

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

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

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

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

    希望对你有帮助!!

    【讨论】:

      【解决方案3】:
      1. Wait 方法用于挂起对象上的当前线程。 等待方法不是来自线程类,而是来自 java.lang.Object

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

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-22
        • 1970-01-01
        • 2014-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多