模块  java.base

Interface Condition

  • 所有已知实现类:
    AbstractQueuedLongSynchronizer.ConditionObjectAbstractQueuedSynchronizer.ConditionObject

    public interface Condition
    Condition因素出Object监视器方法( waitnotifynotifyAll )到不同的对象,以得到具有多个等待集的每个对象,通过将它们与使用任意的组合的效果Lock实现。 如果Lock替换了synchronized方法和语句的使用,则Condition将替换Object监视方法的使用。

    条件(也称为条件队列条件变量 )为一个线程提供暂停执行(“等待”)的手段,直到另一个线程通知某个状态条件现在可能为真。 由于对此共享状态信息的访问发生在不同的线程中,因此必须对其进行保护,因此某种形式的锁定与该条件相关联。 等待条件提供的关键属性是它以原子方式释放关联的锁并挂起当前线程,就像Object.wait一样。

    Condition实例本质上绑定到锁。 为了获得Condition实例特定Lock实例使用其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语句中的目标,并且可以调用自己的监视器waitnotify方法。 获取Condition实例的监视器锁定或使用其监视方法与获取与该Condition关联的Condition或使用其waitingsignalling方法没有指定关系。 为避免混淆,建议您不要以这种方式使用Condition实例,除非在他们自己的实现中。

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

    实施注意事项

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

    条件等待的三种形式(可中断,不可中断和定时)可能在某些平台上的易实现性和性能特征上有所不同。 特别是,可能难以提供这些特征并保持特定的语义,例如订购保证。 此外,在所有平台上实现中断线程的实际暂停的能力可能并不总是可行的。

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

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

    由于中断通常意味着取消,并且中断检查通常不常见,因此实现可以有利于响应正常方法返回的中断。 即使可以显示中断发生在可能已取消阻塞线程的另一个操作之后,也是如此。 实现应记录此行为。

    从以下版本开始:
    1.5
    • 方法摘要

      所有方法  实例方法 抽象方法 
      变量和类型 方法 描述
      void await()
      导致当前线程等到发出信号或 interrupted
      boolean await​(long time, TimeUnit unit)
      导致当前线程等待,直到发出信号或中断,或者指定的等待时间过去。
      long awaitNanos​(long nanosTimeout)
      导致当前线程等待,直到发出信号或中断,或者指定的等待时间过去。
      void awaitUninterruptibly()
      导致当前线程等待直到发出信号。
      boolean awaitUntil​(Date deadline)
      导致当前线程等待,直到发出信号或中断,或者指定的截止时间过去。
      void signal()
      唤醒一个等待线程。
      void signalAll()
      唤醒所有等待的线程。
    • 方法详细信息

      • await

        void await()
            throws InterruptedException
        导致当前线程等到发出信号或interrupted

        与此相关的锁Condition以原子方式释放,并且当前线程的线程调度目的就退出,一直处于休眠状态的四两件事发生对象

        • 一些其他线程为此Condition调用signal()方法,并且当前线程恰好被选为要被唤醒的线程; 要么
        • 其他一些线程为此Condition调用signalAll()方法; 要么
        • 一些其他线程interrupts当前线程,并支持线程挂起的中断; 要么
        • 发生“ 虚假唤醒 ”。

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

        如果当前线程:

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

        实施注意事项

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

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

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

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

        与此条件相关的锁以原子方式释放,并且当前线程的线程调度目的就退出,一直处于休眠状态的三种情况之一发生:

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

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

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

        实施注意事项

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

      • awaitNanos

        long awaitNanos​(long nanosTimeout)
                 throws InterruptedException
        导致当前线程等待,直到发出信号或中断,或者指定的等待时间过去。

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

        • 其他一些线程为此Condition调用signal()方法,并且当前线程恰好被选为要被唤醒的线程; 要么
        • 其他一些线程为此Condition调用signalAll()方法; 要么
        • 一些其他线程interrupts当前线程,并支持线程挂起中断; 要么
        • 指定的等待时间过去了; 要么
        • 发生“ 虚假唤醒 ”。

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

        如果当前线程:

        • 在进入此方法时设置其中断状态; 要么
        • 是等待和中断线程挂起是interrupted
        然后抛出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
        导致当前线程等待,直到发出信号或中断,或者指定的截止时间过去。

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

        • 一些其他线程为此Condition调用signal()方法,并且当前线程恰好被选为要被唤醒的线程; 要么
        • 其他一些线程为此Condition调用signalAll()方法; 要么
        • 一些其他线程interrupts当前线程,并支持线程挂起中断; 要么
        • 指定的截止日期过去了; 要么
        • 发生“ 虚假唤醒 ”。

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

        如果当前线程:

        • 在进入此方法时设置其中断状态; 要么
        • 是等待和中断线程挂起是interrupted
        然后抛出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之类的异常。