java.util.concurrent.locks.Condition awaitUninterruptibly()

时间:2015-01-14 07:53:40

标签: java multithreading concurrency wait

我正在阅读java.util.concurrent.locks.Condition API文档,

我明白了:

  

在等待条件时,允许“虚假唤醒”   通常,作为对底层平台的让步   语义。这对大多数应用程序几乎没有实际影响   程序作为条件应始终在循环中等待,   测试正在等待的状态谓词。一个   实施是免费的,以消除虚假唤醒的可能性   但建议应用程序员始终假设这一点   它们可以发生,因此总是在循环中等待

和awaitUninterruptibly()说:

  

如果当前线程进入此状态时设置了当前线程的中断状态   方法,或等待时中断,它将继续等待   直到发出信号。当它最终从这个方法返回时它   中断状态仍将设置

那么,是否意味着我们不需要在循环中调用awaitUninterruptibly()?请澄清。提前谢谢。

2 个答案:

答案 0 :(得分:3)

specification is pretty clear

  

void awaitUninterruptibly()

     

使当前线程等待直到发出信号。   与此条件关联的锁被原子释放,并且当前线程因线程调度而被禁用,并且处于休眠状态,直到一个三件事情发生:

     
      
  • 其他一些线程为此Condition调用signal()方法,当前线程恰好被选为要被唤醒的线程;或
  •   
  • 其他一些线程为此Condition调用signalAll()方法;或
  •   
  • 发生“虚假唤醒”。
  •   

因此,中断不在可能的唤醒条件列表中,但是虚假唤醒。不要让您通过查看特定的实现代码来指导。您的应用程序最终运行的实现可能完全不同。

此外,Conditioninterface,即使在一个运行时环境中也可能有不同的实现。 This answer甚至没有指定此代码来自哪个具体类。

您必须使用awaitUninterruptibly()的常规循环执行等待操作。

请考虑以下事项:

  • 信号和等待之间没有1:1的映射,
    • 因此您可能会错过在线程醒来之前发生的一个或多个信号
    • 更糟糕的是,信号不会被记住,因此在另一个线程开始等待之前就会丢失信号
  • 因此,在决定等待之前,您必须预先检查所需的条件状态
  • 这意味着一个信号可能唤醒一个线程,但另一个线程由于成功的预检查而消耗该状态,因此醒来的线程必须重新检查所需的条件状态

因此,即使没有虚假的唤醒,也需要在等待之前预先检查并在唤醒后重新检查的循环。

答案 1 :(得分:2)

来自代码:

public final void awaitUninterruptibly() {
  Node node = addConditionWaiter();
  int savedState = fullyRelease(node);
  boolean interrupted = false;
  while (!isOnSyncQueue(node)) {
    LockSupport.park(this);
    if (Thread.interrupted()) interrupted = true;
  }
  if (acquireQueued(node, savedState) || interrupted) selfInterrupt();
}

所以等待是在一个循环中完成的,这将消除在该函数之外循环的需要。

但是请记住,这也意味着Thread.interrupt()不会做任何事情,这可能会导致代码的某些锁定,即使用。在关机期间。