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

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

- 编辑 -

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

4

3 回答 3

4

当一个线程在某个监视器上调用 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();            
        }
    }
}
于 2015-05-27T12:53:24.583 回答
2

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

正如人们已经指出的那样,唤醒线程并不是唯一的结果,但是t1.interrupt()从 Thread调用t2fort1会导致in 线程 t1 ,这是andInterruptedException之间的一个很大区别。Object.notify()Thread.interrupt()

您应该了解它的方法Object.wait()会抛出检查InterruptedException并强制您处理它。对象.等待

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

然后你应该参考这个问题来了解如何处理这个异常。

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

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

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

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

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

希望能帮助到你 !!

于 2017-01-29T13:56:55.573 回答
0
  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)正在使用 Telephone 对象并且正在执行某个任务但调用了中断方法,则 A 将收到信号以停止当前任务,并且可能需要执行分配的其他任务。
于 2015-05-27T12:54:38.327 回答