java condition_(原创)Java的ReentrantLock(可重入锁)下的Condition

本文深入探讨了Java并发编程中Condition与ReentrantLock的关系及其使用机制。详细解析了Condition的await()和signal()方法的工作流程,包括如何利用ReentrantLock进行线程同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先来看一下这个Condition的使用场景,在LinkedBlockingQueue(链表的阻塞队列)类中包含如下的定义,通过使用lock.newCondition()方法,可以获得一个Condition对象,说明Condition与ReentrantLock有着重要的关联关系。

3c09125f0cb467543422515dc3793a60.png

Condition对象创建

通常它们的使用方式是如下这样,注意线程1的condition.await()和线程2的condition.signal()方法,后面重点讲解这两个方法。

df8be13ac01b686e199042a4c896abca.png

例子

Condition类是AQS(AbstractQueuedSynchronizer,抽象的队列同步器)的内部类,我们重点来看下这个线程1的condition.await()方法,对里面的几个重要方法进行重点的说明。

ea3c94cc305caf1d006844c7e60755e3.png

await()方法

Node node = addConditionWaiter();//将当前线程包装成Node,然后放入条件等待队列中,注意这个队列和//外面的ReentrantLock的同步等待队列是两个不同的队列,在唤醒时(也就是调用condition.signal()),会把//这个线程先从条件等待队列中移除,然后转移到ReentrantLock的同步等待队列里面去,然后在同步等待队列//中获取锁以后,才能真正的被执行int savedState = fullyRelease(node);//在将当前线程放入到条件等待队列中以后,这个方法会把当前线程//所持有的锁释放掉,这个时候ReentrantLock同步等待队列中的某一个线程会获得锁,然后被激活int interruptMode = 0;while (!isOnSyncQueue(node)) {//判断当前线程如果不存在于ReentrantLock同步队列中,则将当前线程//中断挂起,如果这个线程存在于ReentrantLock同步队列中,那么它已经被中断挂起,则不需要再次中断挂起  LockSupport.park(this);

总结来说就是,将当前线程封装成Node,然后加入到条件等待队列中,释放线程持有的锁,然后将此线程中断挂起。

接下来我们重点来看下线程2的condition.signal()方法,对里面的几个重要方法进行重点的说明。

a308c610d786721dfd21341b2468b807.png

signal()方法

if (!isHeldExclusively())//判断此线程是不是ReentrantLock锁的独占线程,如果不是则抛出异常,换言之//只有是ReentrantLock锁的独占线程,才能进行唤醒操作,也就是说在执行condition.await()//和condition.signal()方法时,线程必须拿到ReentrantLock锁才可以进行,这也就是Condition //与ReentrantLock有着必要的关联关系    throw new IllegalMonitorStateException();  Node first = firstWaiter;//拿到条件等待线程的第一个Node  if (first != null)    doSignal(first);//第一个Node不为null时,进行唤醒操作

下面来看下doSignal(first)方法的执行逻辑,重点看下其中的transferForSignal(first)方法。

e56e5416c28a3a85a09688dca8986918.png

doSignal()方法

81acf89dd8a20773e923008a046ef590.png

transferForSignal()方法

if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))//将Node的节点更新为0,如果更新失败,  //则代表此节点已经被取消了,直接返回失败,遍历下一个条件等待队列的节点。    return false;Node p = enq(node);//重点方法,将当前节点由条件等待队列转移到ReentrantLock的同步等待队列的队尾中去        int ws = p.waitStatus;//此时被转移到同步等待队列的Node的waitStatus应该是0,        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))//将此Node节点的waitStatus更新为-1            LockSupport.unpark(node.thread);//此逻辑不会执行,因为线程从条件等待队列只是被转移到了同步 //等待队列,而且是队尾的位置,如果同步等待队列前面有有其他线程,则会优先于它被唤醒。        return true;

在执行了condition.signal()方法后,会将条件等待队列中的线程移除,然后转移到ReentrantLock的同步等待队列中,后面的逻辑就和ReentrantLock(可重入锁)执行同步等待队列中的线程一样了(这个逻辑不清楚可以查看我的此篇文章(原创)Java的ReentrantLock(可重入锁)详解上篇)。

简单总结下,Condition依赖于ReentrantLock,必须拿到ReentrantLock锁以后,才可以进行await()和single()方法,在执行了await()时,会释放持有的ReentrantLock锁,并把自己加入到条件等待队列中去,在执行了single()时,会把线程从条件等待队列转移到ReentrantLock的同步等待队列中去,然后等待被真正的执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值