欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java —— Condition

程序员文章站 2024-02-17 22:54:40
...
public interface Condition

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

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

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

例如,假设我们有一个有限的缓冲区,它支持puttake方法。 如果在一个空的缓冲区尝试一个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(); }
   }
 } 

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

需要注意的是Condition实例只是普通的对象,其本身作为一个目标synchronized语句,可以有自己的监视器waitnotification方法调用。 获取Condition实例的监视器锁或使用其监视方法与获取与该Condition相关联的Condition或使用其waitingsignalling方法没有特定关系。 建议为避免混淆,您永远不会以这种方式使用Condition实例,除了可能在自己的实现之内。

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

注意事项

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

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

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

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

由于中断通常意味着取消,并且检查中断通常是不频繁的,所以实现可以有利于通过正常方法返回来响应中断。 即使可以显示中断发生在另一个可能解除阻塞线程的动作之后,这一点也是如此。 一个实现应该记录这个行为。

方法

参数和类型 方法和描述
void await()

导致当前线程等到发信号或 interrupted

boolean await(long time, TimeUnit unit)

使当前线程等待直到发出信号或中断,或指定的等待时间过去。

long awaitNanos(long nanosTimeout)

使当前线程等待直到发出信号或中断,或指定的等待时间过去。

void awaitUninterruptibly()

使当前线程等待直到发出信号。

boolean awaitUntil(Date deadline)

使当前线程等待直到发出信号或中断,或者指定的最后期限过去。

void signal()

唤醒一个等待线程。

void signalAll()

唤醒所有等待线程。