我看过很多关于这个的帖子。本回答https://stackoverflow.com/a/6701060/2359945通过建议测试中断标志获得 100 赏金。
我测试过这个,它对我不起作用。所以,问题仍然存在,我如何检测虚假唤醒,或者这是不可能的?谢谢。
class TestSpuriousWakeup {
static Thread t1, tInterrupt, tNotify;
// spawn one thread that will be interrupted and be notified
// spawn one thread that will interrupt
// spawn one thread that will notify
public static void main(String[] args) {
System.out.println("*** main Starting");
initThreads();
try {
t1.start();
Thread.sleep(2000);
tNotify.start();
tNotify.join();
Thread.sleep(2000);
tInterrupt.start();
tInterrupt.join();
t1.join();
} catch (InterruptedException e) {
System.out.println("*** Unexpected interrupt in main");
}
System.out.println("*** main Ended.");
}
private static void initThreads() {
t1 = new Thread() {
@Override
public void run() {
System.out.println("ThreadInterruptMe Started ...");
boolean stop = false;
Thread.interrupted(); // clear the interrupted flag
while (!stop) {
try {
System.out.println("ThreadInterruptMe Sleeping 5000ms ...");
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println("ThreadInterruptMe InterruptedException e!");
System.out.println("ThreadInterruptMe e.getCause => " + e.getCause());
System.out.println("ThreadInterruptMe e.getLocalizedMessage => " + e.getLocalizedMessage());
stop = Thread.interrupted();
if (stop) {
System.out.println("ThreadInterruptMe was INTERRUPTED because Thread.interrupted() is true"); // never happens
} else {
System.out.println("ThreadInterruptMe was NOTIFIED because Thread.interrupted() is false"); // always happens
}
} finally {
Thread.interrupted(); // clear the interrupted flag
System.out.println("ThreadInterruptMe InterruptedException finally");
}
}
System.out.println("ThreadInterruptMe Ended.");
}
};
tInterrupt = new Thread() {
@Override
public void run() {
System.out.println(" ThreadInterruptYou Started ... interrupting now!");
t1.interrupt();
System.out.println(" ThreadInterruptYou Ended.");
}
};
tNotify = new Thread() {
@Override
public void run() {
System.out.println(" ThreadNotifyYou Started ... notifying now!");
t1.interrupt();
System.out.println(" ThreadNotifyYou Ended.");
}
};
}
}
输出:
*** main Starting
ThreadInterruptMe Started ...
ThreadInterruptMe Sleeping 5000ms ...
ThreadNotifyYou Started ... notifying now!
ThreadInterruptMe InterruptedException e!
ThreadNotifyYou Ended.
ThreadInterruptMe e.getCause => null
ThreadInterruptMe e.getLocalizedMessage => sleep interrupted
ThreadInterruptMe was NOTIFIED because Thread.interrupted() is false
ThreadInterruptMe InterruptedException finally
ThreadInterruptMe Sleeping 5000ms ...
ThreadInterruptYou Started ... interrupting now!
ThreadInterruptMe InterruptedException e!
ThreadInterruptMe e.getCause => null
ThreadInterruptMe e.getLocalizedMessage => sleep interrupted
ThreadInterruptMe was NOTIFIED because Thread.interrupted() is false
ThreadInterruptMe InterruptedException finally
ThreadInterruptMe Sleeping 5000ms ...
ThreadInterruptYou Ended.
ThreadInterruptMe InterruptedException finally
ThreadInterruptMe Sleeping 5000ms ...
ThreadInterruptMe InterruptedException finally
ThreadInterruptMe Sleeping 5000ms ...
<infinite loop>
最佳答案
哪些虚假唤醒不是
sleep()
不受虚假唤醒的影响。它用于 hibernate 的低级系统调用可能是,但 Java 会为您处理这个细节,如果它被过早唤醒,则重新进入系统调用。作为用户,您不会受到虚假唤醒的影响。
虚假唤醒也与线程中断无关。那是一个单独的工具。线程永远不会“虚假地中断”。如果您的线程被中断,则意味着有人在您的线程上调用了 Thread.interrupt()
。找到那个代码,你就会找到罪魁祸首。
什么是虚假唤醒
如果您想测试虚假唤醒,请改为使用 Object.wait()
运行测试,因为这是遭受虚假唤醒影响的经典方法。
使用 wait()
的简单方法是简单地调用它,期望它仅在其他线程调用 notify()
时返回。例如,消息发送循环可能是:
for (;;) {
synchronized (monitor) {
if (queue.isEmpty()) { // incorrect
monitor.wait();
}
}
send(queue.remove());
}
如果 wait()
在没有将消息添加到队列的情况下虚假地唤醒,这将失败。解决方案是在 wait()
周围添加一个循环,以便在每次线程被唤醒时验证条件。
for (;;) {
synchronized (monitor) {
while (queue.isEmpty()) { // correct
monitor.wait();
}
}
send(queue.remove());
}
然后,模拟虚假唤醒的最简单方法是简单地调用notify()
而不更改循环条件。
synchronized (monitor) {
monitor.notify();
}
这将对执行 wait()
的线程产生完全相同的效果,就好像它遇到虚假唤醒一样。使用 if
的错误代码不会意识到队列仍然是空的并且会崩溃。使用 while
的正确代码将重新检查条件并安全地重新进入 wait()
调用。
关于java - 如何检测虚假唤醒,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30675085/