Module java.base

Interface Condition

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

public interface Condition
ConditionObject监视器方法(wait, notifynotifyAll)分离为不同的对象,以实现每个对象具有多个等待集的效果,通过将它们与任意的Lock实现结合使用。其中,Lock取代了synchronized方法和语句的使用,Condition取代了Object监视器方法的使用。

条件(也称为条件队列条件变量)提供了一种方式,使一个线程暂停执行(“等待”),直到另一个线程通知某个状态条件现在可能为真。由于对这些共享状态信息的访问发生在不同的线程中,因此必须进行保护,因此某种形式的锁与条件相关联。等待条件提供的关键属性是它原子地释放关联的锁并挂起当前线程,就像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();
     }
   }
 }
 
(The ArrayBlockingQueue class provides this functionality, so there is no reason to implement this sample usage class.)

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

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

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

实现注意事项

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

条件等待的三种形式(可中断、不可中断和定时)在某些平台上的实现难度和性能特征可能有所不同。特别是,可能难以提供这些功能并保持特定语义,如顺序保证。此外,可能无法在所有平台上实现中断线程实际挂起的能力。

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

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

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

自从:
1.5
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    await()
    使当前线程等待,直到被通知或中断
    boolean
    await(long time, TimeUnit unit)
    使当前线程等待,直到被通知或中断,或经过指定的等待时间。
    long
    awaitNanos(long nanosTimeout)
    使当前线程等待,直到被通知或中断,或经过指定的等待时间。
    void
    使当前线程等待,直到被通知。
    boolean
    awaitUntil(Date deadline)
    使当前线程等待,直到被通知或中断,或经过指定的截止时间。
    void
    signal()
    唤醒一个等待的线程。
    void
    唤醒所有等待的线程。
  • Method Details

    • await

      void await() throws InterruptedException
      使当前线程等待,直到被通知或中断

      与此Condition关联的锁被原子地释放,并且当前线程因线程调度目的而被禁用,并处于休眠状态,直到发生以下四种情况之一:

      • 其他某个线程调用此Conditionsignal()方法,并且当前线程恰好被选择为要唤醒的线程;或
      • 其他某个线程调用此ConditionsignalAll()方法;或
      • 其他某个线程中断当前线程,并且支持线程挂起的中断;或
      • 发生“虚假唤醒”。

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

      如果当前线程:

      • 在进入此方法时设置了中断状态;或
      • 在等待时被中断,并且支持线程挂起的中断,
      那么将抛出InterruptedException,并清除当前线程的中断状态。在第一种情况下,未指定在释放锁之前是否进行中断检查。

      实现注意事项

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

      在响应信号时,实现可以更倾向于响应中断而不是正常方法返回。在这种情况下,实现必须确保如果有另一个等待线程,则将信号重定向给另一个等待线程。

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

      void awaitUninterruptibly()
      使当前线程等待直到被通知。与此条件相关联的锁会被原子性地释放,当前线程会被禁用以进行线程调度,并处于休眠状态,直到发生以下三种情况之一:
      • 其他线程调用此Conditionsignal()方法,并且当前线程被选择为要唤醒的线程;或
      • 其他线程调用此ConditionsignalAll()方法;或
      • 发生“虚假唤醒”。

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

      如果当前线程在进入此方法时被设置了中断状态,或者在等待时被中断,它将继续等待直到被通知。当它最终从此方法返回时,它的中断状态仍然被设置。

      实现注意事项

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

    • awaitNanos

      long awaitNanos(long nanosTimeout) throws InterruptedException
      使当前线程等待直到被通知或中断,或者经过指定的等待时间。与此条件相关联的锁会被原子性地释放,当前线程会被禁用以进行线程调度,并处于休眠状态,直到发生以下五种情况之一:
      • 其他线程调用此Conditionsignal()方法,并且当前线程被选择为要唤醒的线程;或
      • 其他线程调用此ConditionsignalAll()方法;或
      • 其他线程中断当前线程,并且支持线程挂起的中断;或
      • 指定的等待时间已过;或
      • 发生“虚假唤醒”。

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

      如果当前线程:

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

      该方法返回在返回时剩余的纳秒数的估计值,或者如果超时则返回小于或等于零的值。此值可用于确定是否以及多长时间重新等待,在等待返回但仍未满足等待条件的情况下。此方法的典型用法如下:

       
       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
      使当前线程等待直到被通知或中断,或者经过指定的截止时间。与此条件相关联的锁会被原子性地释放,当前线程会被禁用以进行线程调度,并处于休眠状态,直到发生以下五种情况之一:
      • 其他线程调用此Conditionsignal()方法,并且当前线程被选择为要唤醒的线程;或
      • 其他线程调用此ConditionsignalAll()方法;或
      • 其他线程中断当前线程,并且支持线程挂起的中断;或
      • 指定的截止时间已过;或
      • 发生“虚假唤醒”。

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

      如果当前线程:

      • 在进入此方法时中断状态被设置;或
      • 在等待时被中断,并且支持线程挂起的中断,
      则会抛出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