public interface Condition
Condition
因素出Object
监视器方法( wait
, notify
和notifyAll
)成不同的对象,以得到具有多个等待集的每个对象,通过将它们与使用任意的组合的效果Lock
个实现。
Lock
替换synchronized
方法和语句的使用, Condition
取代了对象监视器方法的使用。
条件(也称为条件队列或条件变量 )为一个线程暂停执行(“等待”)提供了一种方法,直到另一个线程通知某些状态现在可能为真。 因为访问此共享状态信息发生在不同的线程中,所以它必须被保护,因此某种形式的锁与该条件相关联。 等待条件的关键属性是它原子地释放相关的锁并挂起当前线程,就像Object.wait
。
一个Condition
实例本质上绑定到一个锁。 要获得特定Condition
实例的Condition实例,请使用其newCondition()
方法。
例如,假设我们有一个有限的缓冲区,它支持put
和take
方法。 如果在一个空的缓冲区尝试一个take
,则线程将阻塞直到一个项目可用; 如果put
试图在一个完整的缓冲区,那么线程将阻塞,直到空间变得可用。 我们希望在单独的等待集中等待put
线程和take
线程,以便我们可以在缓冲区中的项目或空间可用的时候使用仅通知单个线程的优化。 这可以使用两个Condition
实例来实现。
class BoundedBuffer {
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(Object 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 Object take() throws InterruptedException {
lock.lock(); try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
} finally { lock.unlock(); }
}
}
( ArrayBlockingQueue
类提供此功能,因此没有理由实现此示例使用类。)
Condition
实现可以提供Object
监视器方法的行为和语义,例如有保证的通知顺序,或者在执行通知时不需要锁定。 如果一个实现提供了这样的专门的语义,那么实现必须记录这些语义。
需要注意的是Condition
实例只是普通的对象,其本身作为一个目标synchronized
语句,可以有自己的监视器wait
和notification
个方法调用。 获取Condition
实例的监视器锁或使用其监视方法与获取与该Condition相关联的Condition
或使用其waiting和signalling方法没有特定关系。 建议为避免混淆,您永远不会以这种方式使用Condition
实例,除了可能在自己的实现之内。
除非另有说明,传递任何参数的null
值将导致NullPointerException
被抛出。
当等待Condition
时,允许发生“ 虚假唤醒 ”,一般来说,作为对底层平台语义的让步。 这对大多数应用程序几乎没有实际的影响,因为Condition
应该始终在循环中等待,测试正在等待的状态谓词。 一个实现可以免除虚假唤醒的可能性,但建议应用程序员总是假定它们可以发生,因此总是等待循环。
条件等待(可中断,不可中断和定时)的三种形式在一些平台上的易用性和性能特征可能不同。 特别地,可能难以提供这些特征并保持特定的语义,例如排序保证。 此外,中断线程实际挂起的能力可能并不总是在所有平台上实现。
因此,不需要一个实现来为所有三种形式的等待定义完全相同的保证或语义,也不需要支持中断线程的实际暂停。
需要一个实现来清楚地记录每个等待方法提供的语义和保证,并且当一个实现确实支持线程挂起中断时,它必须遵守该接口中定义的中断语义。
由于中断通常意味着取消,并且检查中断通常是不频繁的,所以实现可以有利于通过正常方法返回来响应中断。 即使可以显示中断发生在另一个可能解除阻塞线程的动作之后,这一点也是如此。 一个实现应该记录这个行为。
Modifier and Type | Method and Description |
---|---|
void |
await()
导致当前线程等到发信号或
interrupted 。
|
boolean |
await(long time, TimeUnit unit)
使当前线程等待直到发出信号或中断,或指定的等待时间过去。
|
long |
awaitNanos(long nanosTimeout)
使当前线程等待直到发出信号或中断,或指定的等待时间过去。
|
void |
awaitUninterruptibly()
使当前线程等待直到发出信号。
|
boolean |
awaitUntil(Date deadline)
使当前线程等待直到发出信号或中断,或者指定的最后期限过去。
|
void |
signal()
唤醒一个等待线程。
|
void |
signalAll()
唤醒所有等待线程。
|
void await() throws InterruptedException
与此相关的锁Condition
以原子方式释放,并且当前线程的线程调度目的就退出,一直处于休眠状态的四两件事发生对象 :
signal()
方法本Condition
和当前线程碰巧被选择作为被唤醒线程; 要么 Condition
; 要么 在所有情况下,在此方法返回之前,当前线程必须重新获取与此条件相关的锁。 当线程返回时,它保证保持此锁。
如果当前线程:
InterruptedException
被关上,当前线程的中断状态被清除。
在第一种情况下,没有规定在释放锁之前是否发生中断测试。
实施注意事项
当调用此方法时,假定当前线程保持与此Condition
的锁。 由执行决定是否是这种情况,如果没有,应如何回应。 通常,将抛出异常(例如IllegalMonitorStateException
),并且实现必须记录该事实。
响应于信号,实现可以有利于响应正常方法返回的中断。 在这种情况下,实现必须确保信号被重定向到另一个等待的线程(如果有的话)。
InterruptedException
- 如果当前线程中断(支持线程中断)
void awaitUninterruptibly()
与此条件相关的锁以原子方式释放,并且当前线程的线程调度目的就退出,一直处于休眠状态的三种情况之一发生:
signal()
方法,这个Condition
和当前线程恰好被选择为被唤醒的线程; 要么 signalAll()
方法为这Condition
; 要么 在所有情况下,在此方法返回之前,当前线程必须重新获取与此条件相关的锁。 当线程返回时,它保证保持此锁。
如果当前线程的中断状态在进入此方法时设置,或者等待时为interrupted ,则会继续等待直到发信号。 当它最终从该方法返回时,它的中断状态将仍然被设置。
实施注意事项
当调用此方法时,假定当前线程保持与此Condition
的锁定。 由执行决定是否是这种情况,如果没有,应如何回应。 通常,将抛出异常(如IllegalMonitorStateException
),实现必须记录该事实。
long awaitNanos(long nanosTimeout) throws InterruptedException
与此条件相关的锁以原子方式释放,并且当前线程的线程调度目的就退出,一直处于休眠状态的五件事情发生对象 :
signal()
方法本Condition
和当前线程碰巧被选择作为被唤醒线程; 要么 signalAll()
方法为这Condition
; 要么 在所有情况下,在此方法返回之前,当前线程必须重新获取与此条件相关的锁。 当线程返回时,它保证保持此锁。
如果当前线程:
InterruptedException
被关上,当前线程的中断状态被清除。
在第一种情况下,没有规定在释放锁之前是否发生中断测试。
该方法在返回时返回给出所提供的nanosTimeout
值时剩余的纳秒数的估计,或者如果超时,小于或等于零的值。 该值可用于确定等待返回但待机状态仍然不成立的情况下是否以及等待多长时间。 此方法的典型用途如下:
boolean aMethod(long timeout, TimeUnit unit) { long nanos = unit.toNanos(timeout); lock.lock(); try { while (!conditionBeingWaitedFor()) { if (nanos <= 0L) return false; nanos = theCondition.awaitNanos(nanos); } // ... } finally { lock.unlock(); } }
设计说明:此方法需要一个纳秒参数,以避免报告剩余时间中的截断错误。 这样的精度损失将使程序员难以确保在重新等待时总的等待时间不会比指定时间短。
实施注意事项
当调用此方法时,假定当前线程保持与此Condition
的锁定。 由执行决定是否是这种情况,如果没有,应如何回应。 通常,将抛出异常(例如IllegalMonitorStateException
),并且实现必须记录该事实。
一个实现可以有助于响应于信号响应正常方法返回的中断,或者指示经过指定的等待时间。 在任一情况下,实现必须确保信号被重定向到另一个等待线程(如果有的话)。
nanosTimeout
- 等待的最长时间,以纳秒为单位
nanosTimeout
值减去等待从此方法返回的时间。
可以使用正值作为随后调用此方法的参数,以完成等待所需时间。
小于或等于零的值表示没有时间。
InterruptedException
- 如果当前线程被中断(并且支持线程中断)
boolean await(long time, TimeUnit unit) throws InterruptedException
awaitNanos(unit.toNanos(time)) > 0
time
- 等待的最长时间
unit
-
time
参数的时间单位
false
如果等待时间可以从方法返回前经过,否则
true
InterruptedException
- 如果当前线程被中断(并且支持线程中断的中断)
boolean awaitUntil(Date deadline) throws InterruptedException
与此条件相关的锁以原子方式释放,并且当前线程的线程调度目的就退出,一直处于休眠状态的五件事情发生对象 :
signal()
方法本Condition
和当前线程碰巧被选择作为被唤醒线程; 要么 signalAll()
方法为这Condition
; 要么 在所有情况下,在此方法返回之前,当前线程必须重新获取与此条件相关的锁。 当线程返回时,它保证保持此锁。
如果当前线程:
InterruptedException
被关上,当前线程的中断状态被清除。
在第一种情况下,没有规定在释放锁之前是否发生中断测试。
返回值表示截止期限是否过去,可以如下使用:
boolean aMethod(Date deadline) { boolean stillWaiting = true; lock.lock(); try { while (!conditionBeingWaitedFor()) { if (!stillWaiting) return false; stillWaiting = theCondition.awaitUntil(deadline); } // ... } finally { lock.unlock(); } }
实施注意事项
当调用此方法时,假定当前线程保持与此Condition
的锁定。 由执行决定是否是这种情况,如果没有,应如何回应。 通常,将抛出异常(如IllegalMonitorStateException
),实现必须记录该事实。
一个实现可以有助于响应于信号响应正常方法返回的中断,或者指示通过指定的期限。 在任一情况下,实现必须确保信号被重定向到另一个等待线程(如果有的话)。
deadline
- 绝对等待的时间
false
如果退货期限已过,否则
true
InterruptedException
- 如果当前线程被中断(并且支持线程中断的中断)
void signal()
如果任何线程正在等待此条件,则选择一个线程进行唤醒。 那个线程必须在从await
之前重新获取锁。
实施注意事项
当调用此方法时,实现可能(通常是)要求当前线程保存与此Condition
的锁。 执行必须记录此前提条件,如果不保持锁定,则采取任何措施。 通常情况下,一个异常如IllegalMonitorStateException
将被抛出。
void signalAll()
如果任何线程正在等待这个条件,那么它们都被唤醒。 每个线程必须重新获取锁,才能从await
返回。
实施注意事项
当调用此方法时,实现可能(通常是)要求当前线程保持与此Condition
的锁。 执行必须记录此前提条件,如果不保持锁定,则采取任何措施。 通常情况下,一个异常如IllegalMonitorStateException
将被抛出。