JDK7中Condition源码概述

来源:互联网 发布:网络 神曲 编辑:程序博客网 时间:2024/05/19 09:12
Condition是java.util.concurrent.locks包下的接口,通常作为条件同ReentrantLock共同使用,存在的已知实现类有:AbstractQueuedLongSynchronizer.ConditionObject, AbstractQueuedSynchronizer.ConditionObject;

Condition将Object监视器方法(wait、notify和notifyAll)分解成截然不同的对象,以便通过将这些对象与任意Lock实现组合使用,为每个对象提供多个等待set(wait-set)。其中Lock替代了synchronized方法和语句的使用,Condition替代了Object监视器方法的使用。条件(也称为条件队列或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为true的另一个线程通知它之前,一直挂起该线程(即让其"等待")。因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁与该条件相关联。等待提供一个条件的主要属性是:以原子方式释放相关的锁,并挂起当前线程,就像Object.wait做的那样。Condition实例实质上被绑定到一个锁上。要为特定Lock实例获得Condition实例,请使用其newCondition()方法。

Condition实现可以提供不同于Object监视器方法的行为和语义,比如受保证的通知排序或者在执行通知时不需要保持一个锁。如果某个实现提供了这样特殊的语义,则该实现必须记录这些语义。Condition 实例只是一些普通的对象,它们自身可以用作synchronized语句中的目标,并且可以调用自己的wait和notification监视器方法。获取Condition实例的监视器锁或者使用其监视器方法,与获取和该Condition相关的Lock或使用其waiting和signalling方法没有什么特定的关系。为了避免混淆,建议除了在其自身的实现中之外,切勿以这种方式使用Condition实例。除非另行说明,否则为任何参数传递null值将导致抛出空指针异常。实现注意事项:在等待Condition时,允许发生"虚假唤醒",这通常作为对基础平台语义的让步。对于大多数应用程序这带来的实际影响很小,因为Condition应该总是在一个循环中被等待,并测试正被等待的状态声明。某个实现可以随意移除可能的虚假唤醒,但建议应用程序程序员总是假定这些虚假

唤醒可能发生,因此总是在一个循环中等待。


三种形式的条件等待(可中断、不可中断和超时)在一些平台上的实现以及它们的性能特征可能会有所不同。尤其是它可能很难提供这些特性和维护特定语义,比如排序保证。更进一步地说,中断线程实际挂起的能力在所有平台上并不是总是可行的。因此并不要求某个实现为所有三种形式的等待定义完全相同的保证或语义,也不要求其支持中断线程的实际挂起。要求实现清楚地记录每个等待方法提供的语义和保证,在某个实现不支持中断线程的挂起时,它必须遵从此接口中定义的中断语义。由于中断通常意味着取消,而又通常很少进行中断检查,因此实现可以先于普通方法的返回来对中断进行响应。即使出现在另一个操作后的中断可能会释放线程锁时也是如此。实现应记录此行为。

Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。不同的是Object中的这些方法是和同步锁捆绑使用的;而Condition是需要与互斥锁/共享锁捆绑使用的。Condition它更强大的地方在于:能够更加精细的控制多线程的休眠与唤醒。对于同一个锁,可以创建多个Condition,在不同的情况下使用不同的Condition。 
 
Condition提供的方法不多,具体说明如下:
void await() throws InterruptedException
造成当前线程在接到信号或被中断之前一直处于等待状态。与此Condition相关的锁以原子方式释放,并且出于线程调度的目的将禁用当前线程,且在发生以下四种情况之一以前,当前线程将一直处于休眠状态:
(1)其它某个线程调用此Condition的signal()方法,并且碰巧将当前线程选为被唤醒的线程;
(2)其它某个线程调用此Condition的signalAll()方法;
(3)其它某个线程中断当前线程且支持中断线程的挂起;
(4)发生"虚假唤醒"
在此方法可以返回当前线程之前,都必须重新获取与此条件有关的锁,在线程返回时可以保证它保持此锁。如果当前线程在进入此方法时已经设置了该线程的中断状态或者在支持等待和中断线程挂起时,线程被中断则抛出InterruptedException并清除当前线程的中断状态。在第一种情况下没有指定是否在释放锁之前发生中断测试。
实现注意事项:假定调用此方法时,当前线程保持了与此Condition有关联的锁。这取决于确定是否为这种情况以及不是时,如何对此作出响应的实现。通常将抛出一个异常,比如IllegalMonitorStateException并且该实现必须对此进行记录。与响应某个信号而返回的普通方法相比,实现可能更喜欢响应某个中断。在这种情况下,实现必须确保信号被重定向到另一个等待线程(如果有的话)。
抛出:InterruptedException-如果当前线程被中断(并且支持中断线程挂起)
 
void awaitUninterruptibly()
类似await()的实现,只不过它不支持其它某个线程中断当前线程,也不支持中断线程的挂起。如果在进入此方法时设置了当前线程的中断状态或者在等待时线程被中断,那么在接到信号之前它将继续等待,当最终从此方法返回时仍然将设置其中断状态。
 
long awaitNanos(long nanosTimeout)throws InterruptedException
类似await()的实现,只不过它的休眠存在指定的等待时间,它返回的是nanosTimeout值减去花费在等待此方法的返回结果的时间的估算。正值可以用作对此方法进行后续调用的参数来完成等待所需时间结束,小于等于零的值表示没有剩余时间。在设计上此方法需要一个nanosecond参数,以避免在报告剩余时间时出现截断错误。在发生重新等待时,这种精度损失使得程序员难以确保总的等待时间不少于指定等待时间。
 
boolean await(long time,TimeUnit unit)throws InterruptedException
此方法在行为上等效于:awaitNanos(unit.toNanos(time))>0
 
boolean awaitUntil(Date deadline)throws InterruptedException
此方法在行为上等效于:awaitNanos(unit.toNanos(time))>0
 
void signal()
唤醒一个等待线程,如果所有的线程都在等待此条件则选择其中的一个唤醒,在从await返回之前该线程必须重新获取锁。
 
void signalAll()
类似signal()的实现,它们的差别是signalAll()会唤醒所有的等待线程,但也只有一个线程可以获得锁。
原创粉丝点击