标签:long ted bsp 示例 检查 关联 总结 释放 height
在java中,对于任意一个java对象,它都拥有一组定义在java.lang.Object
上监视器方法,包括wait()
,wait(long timeout)
,notify()
,notifyAll()
,这些方法配合synchronized关键字一起使用可以实现等待/通知模式。
同样,Condition接口也提供了类似Object监视器的方法,通过与Lock配合来实现等待/通知模式。
为了更好的了解Condition的特性,我们来对比一下两者的使用方式以及功能特性:
对比项 | Object监视器 | Condition |
---|---|---|
前置条件 | 获取对象的锁 | 调用Lock.lock获取锁,调用Lock.newCondition获取Condition对象 |
调用方式 | 直接调用,比如object.notify() | 直接调用,比如condition.await() |
等待队列的个数 | 一个 | 多个 |
当前线程释放锁进入等待状态 | 支持 | 支持 |
当前线程释放锁进入等待状态,在等待状态中不断响中断 | 不支持 | 支持 |
当前线程释放锁并进入超时等待状态 | 支持 | 支持 |
当前线程释放锁并进入等待状态直到将来的某个时间 | 不支持 | 支持 |
唤醒等待队列中的一个线程 | 支持 | 支持 |
唤醒等待队列中的全部线程 | 支持 | 支持 |
实现一个简单的有界队列,队列为空时,队列的删除操作将会阻塞直到队列中有新的元素,队列已满时,队列的插入操作将会阻塞直到队列出现空位。
不难看出,Condition的使用方式是比较简单的,需要注意的是使用Condition的等待/通知需要提前获取到与Condition对象关联的锁,Condition对象由Lock对象创建。
以上述示例中的add(T object)为例,详细描述一下Condition等待/通知的整个过程:
总的来说,Condition的等待/通知使用方式大体上跟经典的Object监视器上的等待/通知是非常类似的。
Condition提供以下接口以供实现:
void await() throws InterruptedException
当前线程进入等待状态,直到被通知(signal)或者被中断时,当前线程进入运行状态,从await()返回;
void awaitUninterruptibly()
当前线程进入等待状态,直到被通知,对中断不做响应;
long awaitNanos(long nanosTimeout) throws InterruptedException
在接口1的返回条件基础上增加了超时响应,返回值表示当前剩余的时间,如果在nanosTimeout之前被唤醒,返回值 = nanosTimeout - 实际消耗的时间,返回值 <= 0表示超时;
boolean await(long time, TimeUnit unit) throws InterruptedException
同样是在接口1的返回条件基础上增加了超时响应,与接口3不同的是:
boolean awaitUntil(Date deadline) throws InterruptedException
当前线程进入等待状态直到将来的指定时间被通知,如果没有到指定时间被通知返回true,否则,到达指定时间,返回false;
void signal()
唤醒一个等待在Condition上的线程;
void signalAll()
唤醒等待在Condition上所有的线程。
ConditionObject是Condition在java并发中的具体的实现,它是AQS的内部类。因为Condition相关操作都需要获取锁,所以作为AQS的内部类也比较合理。接下来就以ConditionObject的等待队列、等待、通知为切入点分析ConditionObject的具体实现。
ConditionObject的等待队列是一个FIFO队列,队列的每个节点都是等待在Condition对象上的线程的引用,在调用Condition的await()方法之后,线程释放锁,构造成相应的节点进入等待队列等待。其中节点的定义复用AQS的Node定义。
等待队列相关操作实现
从队列相关操作的具体实现可以知道等待队列的基本结构如下图所示:
插入节点只需要将原有尾节点的nextWaiter指向当前节点,并且更新尾节点。更新节点并没有像AQS更新同步队列使用CAS是因为调用await()方法的线程必定是获取了锁的线程,锁保证了操作的线程安全。
注:AQS实质上拥有一个同步队列和多个等待队列,具体对应关系如下图所示:
调用Condition的await开头的系列方法,当前线程进入等待队列等待,那么Condition的等待实质是await系列方法的具体实现。
await实现
其他以await开头的方法具体实现与await基本一致,只是在它的基础上增加了超时限制,不管有没有被唤醒,到达指定时间,等待结束,从await返回。整个await系列方法将线程加入等待队列的流程可以总结为下图:
调用Condition的signal()方法将会唤醒再等待队列中的首节点,该节点也是到目前为止等待时间最长的节点。
signal实现
可以看出,doSignal方法是整个signal方法实现的核心,它完成了将线程从唤醒的所有操作。
doSignal实现
transferForSignal实现
Condition的signalAll()方法,将等待队列中的所有节点全部唤醒,相当于将等待队列中的每一个节点都执行一次signal()。整个signal系列方法将线程从等待队列移动到同步队列可以总结为下图:
zbb20180929 thread java并发编程之Condition
标签:long ted bsp 示例 检查 关联 总结 释放 height
原文地址:https://www.cnblogs.com/super-admin/p/9727035.html