如何检测虚假唤醒 [英] How to Detect a Spurious Wakeup

查看:168
本文介绍了如何检测虚假唤醒的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经阅读了很多这方面的帖子。这个答案 https://stackoverflow.com/a/6701060/2359945 通过建议测试中断的旗帜获得了100的赏金。

I have read many posts on this. This answer https://stackoverflow.com/a/6701060/2359945 claimed a 100 bounty by suggesting to test the interrupted flag.

我对此进行了测试,但它对我不起作用。所以,问题仍然存在,如何检测虚假唤醒,或者不可能?谢谢。

I tested this, and it does not work for me. So, the question remains, how do I detect a spurious wakeup, or is it not possible? Thank you.

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>


推荐答案

通过重新测试谓词来检测虚假唤醒。

You detect a spurious wakeup by re-testing the predicate.

如果没有理由进行唤醒,则唤醒是假的。如果其他一些线程故意唤醒你,唤醒并不是虚假的。

A wakeup is spurious if there is no reason for the wakeup. A wakeup is not spurious if some other thread intentionally woke you.

或者,更简单地说:如果你等待的东西没有发生,那么唤醒是假的。如果你正在等待的事情发生了,那么唤醒并不是虚假的。你必须能够检查你正在等待或发生的事情 - 否则,你怎么知道你必须在第一时间等待它?

Or, to put it even more simply: If the thing you were waiting for hasn't happened, the wakeup was spurious. If the thing you were waiting for has happened, the wakeup was not spurious. You have to be able to check whether the thing you were waiting or has happened or not -- otherwise, how did you know you had to wait for it in the first place?

所以在一个线程故意唤醒你之前,让它设置一个你醒来时检查的同步变量。如果设置了该变量,则唤醒不是虚假的,您清除该标志。如果没有设置,则唤醒是spuroius,你通常会忽略唤醒。

So before a thread intentionally wakes you, have it set some synchronized variable that you check when you wake up. If that variable is set, then the wakeup was not spurious, and you clear the flag. If it is not set, then the wakeup was spuroius, and you typically ignore the wakeup.

所以,流程如下:

要在线程唤醒/发出信号/中断:

To wake/signal/interrupt at thread:


  1. 获取锁定或输入同步块。

  2. 将布尔谓词设置为true。

  3. 唤醒线程。

  4. 解除锁定或退出同步块。

    (如果需要,可以交换3和4的顺序。)

  1. Acquire a lock or enter a synchronized block.
  2. Set the boolean predicate to true.
  3. Wake the thread.
  4. Release the lock or exit the synchronized block.
    (If desired, the order of 3 and 4 can be swapped.)

等待事情发生:


  1. 获取锁定或输入同步块。

  2. 将布尔谓词设置为false(或检查它是否已设置)。

  3. 等等,释放锁定。唤醒时,重新获取锁定(或重新进入同步块)。

  4. 检查谓词以查看唤醒是否是虚假的。如果谓词为假,请转到步骤3.

  5. 您现在知道唤醒不是虚假的。释放锁定或退出同步块。

  1. Acquire a lock or enter a synchronized block.
  2. Set the boolean predicate to false (or check it if it was already set).
  3. Wait, releasing the lock. When woken, reacquire the lock (or re-enter a synchronized block).
  4. Check the predicate to see if the wake is spurious. If the predicate is false, go to step 3.
  5. You now know the wakeup was not spurious. Release the lock or exit the synchronized block.

这篇关于如何检测虚假唤醒的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆