模块 java.base

接口 Condition

所有已知的实现类:
AbstractQueuedLongSynchronizer.ConditionObject , AbstractQueuedSynchronizer.ConditionObject

public interface Condition
ConditionObject 监视器方法(wait notify notifyAll )分解为不同的对象,通过将它们与任意 Lock 实现的使用相结合,从而产生每个对象具有多个等待集的效果。其中 Lock 替换了 synchronized 方法和语句的使用,Condition 替换了对象监视器方法的使用。

条件(也称为 condition queuescondition variables )为一个线程提供了一种暂停执行(“等待”)的方法,直到另一个线程通知某个状态条件现在可能为真。因为对这种共享状态信息的访问发生在不同的线程中,它必须受到保护,所以某种形式的锁与条件相关联。等待条件提供的关键属性是它 atomically 释放关联的锁并挂起当前线程,就像 Object.wait 一样。

Condition 实例本质上绑定到锁。要获取特定 Lock 实例的 Condition 实例,请使用其 newCondition() 方法。

例如,假设我们有一个支持 puttake 方法的有界缓冲区。如果在空缓冲区上尝试take,则线程将阻塞直到有项可用;如果尝试对满缓冲区执行 put,则线程将阻塞直到有空间可用。我们希望在单独的等待集中等待 put 个线程和 take 个线程,以便我们可以使用优化,在缓冲区中的项目或空间可用时一次只通知一个线程。这可以使用两个 Condition 实例来实现。

 class BoundedBuffer<E> {
  final Lock lock = new ReentrantLock();
  final Condition notFull = lock.newCondition(); 
  final Condition notEmpty = lock.newCondition(); 

  final Object[] items = new Object[100];
  int putptr, takeptr, count;

  public void put(E x) throws InterruptedException {
   lock.lock();
   try {
    while (count == items.length)
     notFull.await();
    items[putptr] = x;
    if (++putptr == items.length) putptr = 0;
    ++count;
    notEmpty.signal();
   } finally {
    lock.unlock();
   }
  }

  public E take() throws InterruptedException {
   lock.lock();
   try {
    while (count == 0)
     notEmpty.await();
    E x = (E) items[takeptr];
    if (++takeptr == items.length) takeptr = 0;
    --count;
    notFull.signal();
    return x;
   } finally {
    lock.unlock();
   }
  }
 }
 
ArrayBlockingQueue 类提供此功能,因此没有理由实现此示例用法类。)

Condition 实现可以提供与 Object 监视器方法不同的行为和语义,例如保证通知的顺序,或者在执行通知时不需要持有锁。如果一个实现提供了这样的专门语义,那么该实现必须记录这些语义。

请注意,Condition 实例只是普通对象,它们本身可以用作 synchronized 语句中的目标,并且可以调用自己的监视器 wait notify 方法。获取 Condition 实例的监视器锁,或使用其监视器方法,与获取与该 Condition 关联的 Lock 或使用其 等待信号 方法没有特定关系。建议您不要以这种方式使用 Condition 实例,以避免混淆,除非在它们自己的实现中。

除非另有说明,否则为任何参数传递 null 值将导致抛出 NullPointerException

实现注意事项

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

三种形式的条件等待(可中断、不可中断和定时)在某些平台上的易用性和性能特征方面可能有所不同。特别是,可能很难提供这些功能并维护特定的语义,例如顺序保证。此外,中断线程实际挂起的能力可能并不总是在所有平台上都可行。

因此,不需要实现为所有三种形式的等待定义完全相同的保证或语义,也不需要支持线程实际挂起的中断。

需要一个实现来清楚地记录每个等待方法提供的语义和保证,并且当一个实现确实支持线程挂起的中断时,它必须遵守此接口中定义的中断语义。

由于中断通常意味着取消,并且通常很少检查中断,因此实现可能更倾向于响应中断而不是正常的方法返回。即使可以证明中断发生在另一个可能解除线程阻塞的操作之后也是如此。一个实现应该记录这种行为。

自从:
1.5
  • 方法总结

    修饰符和类型
    方法
    描述
    void
    导致当前线程等待,直到收到信号或 interrupted
    boolean
    await(long time, TimeUnit unit)
    使当前线程等待,直到收到信号或中断,或者指定的等待时间结束。
    long
    awaitNanos(long nanosTimeout)
    使当前线程等待,直到收到信号或中断,或者指定的等待时间结束。
    void
    导致当前线程等待直到收到信号。
    boolean
    awaitUntil(Date deadline)
    使当前线程等待,直到它收到信号或被中断,或者指定的截止日期过去。
    void
    唤醒一个等待线程。
    void
    唤醒所有等待的线程。
  • 方法详情

    • await

      void await() throws InterruptedException
      导致当前线程等待,直到收到信号或 interrupted

      与此 Condition 关联的锁被自动释放,当前线程因线程调度目的而被禁用并处于休眠状态,直到 one 发生以下四件事:

      • 某个其他线程为这个Condition调用了signal() 方法,而当前线程恰好被选为要被唤醒的线程;或者
      • 一些其他线程为此 Condition 调用 signalAll() 方法;或者
      • 其他线程中断当前线程,支持中断线程挂起;或者
      • 出现“spurious wakeup”。

      在所有情况下,在此方法可以返回之前,当前线程必须重新获取与此条件关联的锁。当线程返回时是guaranteed持有这个锁。

      如果当前线程:

      • 在进入此方法时设置其中断状态;或者
      • interrupted while等待和中断线程挂起是支持的,
      然后抛出InterruptedException 并清除当前线程的中断状态。未指定,在第一种情况下,是否在释放锁之前进行中断测试。

      实现注意事项

      调用此方法时,假定当前线程持有与此 Condition 关联的锁。由实施来确定是否是这种情况,如果不是,如何回应。通常,会抛出异常(例如 IllegalMonitorStateException )并且实现必须记录该事实。

      一个实现可以优先响应中断而不是响应信号的正常方法返回。在那种情况下,实现必须确保信号被重定向到另一个等待线程(如果有的话)。

      抛出:
      InterruptedException - 如果当前线程被中断(并且支持中断线程挂起)
    • awaitUninterruptibly

      void awaitUninterruptibly()
      导致当前线程等待直到收到信号。

      与此条件关联的锁被自动释放,当前线程因线程调度目的而被禁用并处于休眠状态,直到 one 发生以下三件事:

      • 某个其他线程为这个Condition调用了signal() 方法,而当前线程恰好被选为要被唤醒的线程;或者
      • 一些其他线程为此 Condition 调用 signalAll() 方法;或者
      • 出现“spurious wakeup”。

      在所有情况下,在此方法可以返回之前,当前线程必须重新获取与此条件关联的锁。当线程返回时是guaranteed持有这个锁。

      如果进入该方法时设置了当前线程的中断状态,或者在等待时为interrupted,则会继续等待直到有信号。当它最终从此方法返回时,它的中断状态仍将被设置。

      实现注意事项

      调用此方法时,假定当前线程持有与此 Condition 关联的锁。由实施来确定是否是这种情况,如果不是,如何回应。通常,会抛出异常(例如 IllegalMonitorStateException )并且实现必须记录该事实。

    • awaitNanos

      long awaitNanos(long nanosTimeout) throws InterruptedException
      使当前线程等待,直到收到信号或中断,或者指定的等待时间结束。

      与此条件关联的锁被自动释放,当前线程因线程调度目的而被禁用并处于休眠状态,直到发生以下五件事中的 one

      • 某个其他线程为这个Condition调用了signal() 方法,而当前线程恰好被选为要被唤醒的线程;或者
      • 一些其他线程为此 Condition 调用 signalAll() 方法;或者
      • 其他线程中断当前线程,支持中断线程挂起;或者
      • 指定的等待时间过去了;或者
      • 出现“spurious wakeup”。

      在所有情况下,在此方法可以返回之前,当前线程必须重新获取与此条件关联的锁。当线程返回时是guaranteed持有这个锁。

      如果当前线程:

      • 在进入此方法时设置其中断状态;或者
      • interrupted while等待和中断线程挂起是支持的,
      然后抛出InterruptedException 并清除当前线程的中断状态。未指定,在第一种情况下,是否在释放锁之前进行中断测试。

      给定返回时提供的 nanosTimeout 值,该方法返回等待等待的剩余纳秒数的估计值,如果超时则返回小于或等于零的值。在等待返回但等待条件仍然不成立的情况下,此值可用于确定是否重新等待以及重新等待多长时间。此方法的典型用法采用以下形式:

       
       boolean aMethod(long timeout, TimeUnit unit)
         throws InterruptedException {
        long nanosRemaining = unit.toNanos(timeout);
        lock.lock();
        try {
         while (!conditionBeingWaitedFor()) {
          if (nanosRemaining <= 0L)
           return false;
          nanosRemaining = theCondition.awaitNanos(nanosRemaining);
         }
         // ...
         return true;
        } finally {
         lock.unlock();
        }
       } 

      设计说明:此方法需要一个纳秒参数,以避免在报告剩余时间时出现截断错误。这种精度损失将使程序员难以确保总等待时间不会系统地短于重新等待发生时指定的时间。

      实现注意事项

      调用此方法时,假定当前线程持有与此 Condition 关联的锁。由实施来确定是否是这种情况,如果不是,如何回应。通常,会抛出异常(例如 IllegalMonitorStateException )并且实现必须记录该事实。

      一个实现可以优先响应中断而不是响应信号的正常方法返回,或者优先于指示指定等待时间的过去。在任何一种情况下,实现都必须确保将信号重定向到另一个等待线程(如果有的话)。

      参数:
      nanosTimeout - 等待的最长时间,以纳秒为单位
      返回:
      nanosTimeout 值的估计值减去等待从此方法返回所花费的时间。正值可用作后续调用此方法的参数以完成等待所需时间。小于或等于零的值表示没有时间剩余。
      抛出:
      InterruptedException - 如果当前线程被中断(并且支持中断线程挂起)
    • await

      boolean await(long time, TimeUnit  unit) throws InterruptedException
      使当前线程等待,直到收到信号或中断,或者指定的等待时间结束。此方法在行为上等同于:
       awaitNanos(unit.toNanos(time)) > 0 
      参数:
      time - 最长时间等待
      unit - time 参数的时间单位
      返回:
      false 如果在从方法返回之前可检测到等待时间已经过去,否则 true
      抛出:
      InterruptedException - 如果当前线程被中断(并且支持中断线程挂起)
    • awaitUntil

      boolean awaitUntil(Date  deadline) throws InterruptedException
      使当前线程等待,直到它收到信号或被中断,或者指定的截止日期过去。

      与此条件关联的锁被自动释放,当前线程因线程调度目的而被禁用并处于休眠状态,直到发生以下五件事中的 one

      • 某个其他线程为这个Condition调用了signal() 方法,而当前线程恰好被选为要被唤醒的线程;或者
      • 一些其他线程为此 Condition 调用 signalAll() 方法;或者
      • 其他线程中断当前线程,支持中断线程挂起;或者
      • 指定的截止日期已过;或者
      • 出现“spurious wakeup”。

      在所有情况下,在此方法可以返回之前,当前线程必须重新获取与此条件关联的锁。当线程返回时是guaranteed持有这个锁。

      如果当前线程:

      • 在进入此方法时设置其中断状态;或者
      • interrupted while等待和中断线程挂起是支持的,
      然后抛出InterruptedException 并清除当前线程的中断状态。未指定,在第一种情况下,是否在释放锁之前进行中断测试。

      返回值表示截止日期是否已过,可以按如下方式使用:

       
       boolean aMethod(Date deadline)
         throws InterruptedException {
        boolean stillWaiting = true;
        lock.lock();
        try {
         while (!conditionBeingWaitedFor()) {
          if (!stillWaiting)
           return false;
          stillWaiting = theCondition.awaitUntil(deadline);
         }
         // ...
         return true;
        } finally {
         lock.unlock();
        }
       } 

      实现注意事项

      调用此方法时,假定当前线程持有与此 Condition 关联的锁。由实施来确定是否是这种情况,如果不是,如何回应。通常,会抛出异常(例如 IllegalMonitorStateException )并且实现必须记录该事实。

      一个实现可以优先响应中断而不是响应信号的正常方法返回,或者优先于指示指定截止日期的过去。在任何一种情况下,实现都必须确保将信号重定向到另一个等待线程(如果有的话)。

      参数:
      deadline - 等待的绝对时间
      返回:
      false 如果截止日期已过返回,否则 true
      抛出:
      InterruptedException - 如果当前线程被中断(并且支持中断线程挂起)
    • signal

      void signal()
      唤醒一个等待线程。

      如果有任何线程正在等待这种情况,则选择一个线程进行唤醒。该线程必须在从 await 返回之前重新获取锁。

      实现注意事项

      当调用此方法时,实现可能(并且通常确实)要求当前线程持有与此 Condition 关联的锁。实现必须记录此先决条件以及在未持有锁时采取的任何操作。通常,会抛出 IllegalMonitorStateException 之类的异常。

    • signalAll

      void signalAll()
      唤醒所有等待的线程。

      如果有任何线程正在等待这种情况,那么它们都会被唤醒。每个线程必须重新获取锁才能从 await 返回。

      实现注意事项

      当调用此方法时,实现可能(并且通常确实)要求当前线程持有与此 Condition 关联的锁。实现必须记录此先决条件以及在未持有锁时采取的任何操作。通常,会抛出 IllegalMonitorStateException 之类的异常。