Java同步方式(3)——condition
在 JavaSE5 中新添加了 java.util.concurrent.locks. Condition 接口。
主要包括 await、signal、signalAll 方法来实现休眠和唤醒工作,有点类似与Linux C++的信号通信机制。
Condition 不仅在 API 中实现了 wait/notify 语义,而且提供了几个新的特性,
例如:为每个 Lock 创建多重 Condition、可中断的等待、访问统计信息等。
1、Condition的概念
Condition: Condition接口提供了类似Object的监视器Monitor方法,与Lock配合可以实现等待/通知模式。
当前线程若要调用Condition的相关方法,需要提前获取到Condition对象关联的锁,
Condition对象是由Lock对象的newCondition()创建出来的。Condition是依赖于Lock对象的
等待方法
1、void await() throws InterruptedException;
同Object.wait(),直到被中断或唤醒(死等),如果在等待状态中被其他线程中断会抛出被中断异常;
2、void awaitUninterruptibly();
不响应中断,直到被唤醒(中断也不会返回)<独有>
3、boolean await(long time, TimeUnit unit) throws InterruptedException;
同Object.wait(long timeout),多了自定义时间单位,中断、超时、被唤醒都会被返回(不会死等)
4、boolean awaitUntil(Date deadline) throws InterruptedException;
支持设置截止时间<独有>
Object.wait(long timeout):这是在设置等待多久后停止等待,
而Condition.awaitUtil(Date deadline):设置的是一个截止日期,截止到这个日期时间就停止等待
唤醒方法
1、signal():唤醒一个等待在condition上的线程,将该线程由等待队列转移到同步队列上
2、signalAll():将所有等待在condition上的线程全部转移到同步队列中
Condition 使用实例:
public class ConditionTest { Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); public void conditionWait() throws InterruptedException { lock.lock(); try { condition.await(); }finally { lock.unlock(); } } public void conditionSignal(){ lock.lock(); try { condition.signal(); }finally { lock.unlock(); } } }
调用await()后当前线程会释放锁
并在此等待。调用signal()方法,通知当前线程后,当前线程才从await()方法返回,返回前已经获取了锁。
Condition实现的等待/通知机制与Object的等待/通知机制有什么区别?
2、Condition等待/通知与Object等待/通知的区别
①不同底层实现
Object类提供的wait与noify方法是与对象监视器monitor配合完成线程的等待/通知机制,属于JVM底层实现;而Condition与Lock配合完成的等待/通知机制属于java语言级别,具有更高的控制与扩展性。
②Condition独有特性
a) 支持不响应中断(等待队列
),而Object不支持。
b)支持多个等待队列
(new 多个Condition对象),而Object只支持一个。但无论是Condition还是Object都只有一个同步队列
。
c) 支持超时时间设置,而Object不支持
到底什么才是等待队列?
3、Condition的等待队列
等待队列概念
等待队列是一个
单向
的带有头尾节点的队列,所有调用condition.await()方法的线程会依次
加入到该condition所对应的等待队列中,并且线程状态转换为等待状态。
Lock锁可以拥有一个同步队列和多个等待队列,Object对象监视器只能拥有一个同步队列和一个等待队列。
通过Condition操作实现一个有界队列。
Condition机制到底是怎么运行的?程序调用await()、signal()到底会做什么?
4、Condition机制的流程
①await()
的流程(同步队列->等待队列
)
当前线程调用Condition.await()实际上做了两件事情。
a)释放当前线程的同步状态(锁)
,唤醒在同步队列中头结点的后继节点引用的线程
。(由于当前线程是同步队列的头结点,只有头结点才有资格获取同步资源(锁))——通过AQS的release()方法
b)将当前线程从同步队列中移出,以当前线程构造结点(addConditionWaiter),并将结点尾插入等待队列。
PS:尾插时尾结点的更新并不需要CAS操作,因为能调用await()的线程必是获取了锁的线程)
c)await()的结束:直到该线程再次获得了lock锁(其他线程调用signal进入同步队列+进入同步队列后那一顿操作)后,await()方法才会真正的结束,或者在等待时被中断会做中断处理。
②signal()
的流程(等待队列->同步队列
)
若当前线程以获得线程,调用signal()就可以:将等待队列
的头结点,插入同步队列的
尾部,即唤醒等待时间最长的线程
通过同步队列的流程,最终使得该线程获取到锁,才能使await()真正结束。
③signalAll的流程
signal()只是将等待队列的头结点插入到同步队列尾部,而signalAll()是将整个
等待队列依次
加入到同步队列尾部。
Condition机制的引入的原因是什么?
5、Condition机制的应用
代替Object的wait-notify机制(该机制中的方法属于操作系统中的方法,不易于控制)
参考:
Java并发编程——Condition(wait\signal\notify的等待-通知模式 )
参考推荐:
Java同步方式(2)——wait和notify/notifyall
Java 同步关键字synchronized底层实现原理及锁优化
String、StringBuilder、StringBuffer用法比较
ArrayList、LinkedList、Vector、Map用法比较
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2021-01-22 13:52:33
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!