condition源码分析
2022/4/11 17:12:46
本文主要是介绍condition源码分析,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录:
1:注意事项
condition是ReentrantLock中的对象,使用condition必须配合lock锁一起使用,否则会报错,原因以下会分析
2:创建方式
ReentrantLock lock = new ReentrantLock();
Condition fullCondition =lock.newCondition();
3:使用案例
package com.saytoyou.com.thread; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class ConditionTest { public static void main(String[] args) { ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); new Thread(new Runnable() { @Override public void run() { lock.lock(); System.out.println("你好,我抢到了资源开始执行"); try { condition.await(); System.out.println("我又获取到资源了"); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } }).start(); new Thread(new Runnable() { @Override public void run() { lock.lock(); System.out.println("你好,我是线程signal"); try { condition.signal(); System.out.println("开始释放资源"); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } }).start(); } }
说明:需要注意的是,signal必须是在await方法之前执行,不然会导致死锁,好了接下来进行源码分析
4:源码分析await方法
await源码如下
public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); 加入等待队列 int savedState = fullyRelease(node); 释放当前线程占用的锁资源,因为线程不知道state是几,所以释放完成,返回state的值,保存起来 int interruptMode = 0; while (!isOnSyncQueue(node)) { 循环判断是否在同步队列中,在同步队列中,说明signal调用了,可以进行如下操作,否否则等待 LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) 利用AQS放入阻塞队列,尝试获取资源,等待唤醒 interruptMode = REINTERRUPT; if (node.nextWaiter != null) // clean up if cancelled unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); }
whille()循环详解,刚开始进来肯定不在同步对列中,所以false进入循环,park,等待唤醒,唤醒之后不管下面if循环是否有效,再次进入while循环,这时候
肯定已经在同步队列了,所以会跳出循环,进行接下来的操作
上述addConditionWaiter源码如下
private Node addConditionWaiter() { Node t = lastWaiter; // If lastWaiter is cancelled, clean out. if (t != null && t.waitStatus != Node.CONDITION) { unlinkCancelledWaiters(); 清除队列中不是condition状态的节点 t = lastWaiter; } Node node = new Node(Thread.currentThread(), Node.CONDITION); if (t == null) firstWaiter = node; else t.nextWaiter = node; lastWaiter = node; return node; } 新建一个node节点,赋值为-2也就是condition状态,然后加入到队列尾部,同时把最后一个lastWaiter指向新节点 unlinkCancelledWaiters,方法就是把队列中不是condition状态的节点清楚掉
unlinkCancelledWaiters方法如下
private void unlinkCancelledWaiters() { Node t = firstWaiter; Node trail = null; while (t != null) { Node next = t.nextWaiter; if (t.waitStatus != Node.CONDITION) { t.nextWaiter = null; 帮助gc if (trail == null) firstWaiter = next; else trail.nextWaiter = next; 如果发现状态不正确,就把上个节点剔除,保存当前节点 if (next == null) lastWaiter = trail; } else trail = t; 存放上一个节点 t = next; 存放当前节点,循环往上 } } 大概就是trail保存上一个节点,t保存当前节点,循环往下,如果t节点的下个节点状态不正确,就把t剔除,直接用下一个节点关联到上一个节点
回到addwaiter方法中 int savedState = fullyRelease(node);该方法的主要作用就是释放调用await方法的线程的锁资源,同时临时返回state的值,供后面使用
final int fullyRelease(Node node) { boolean failed = true; try { int savedState = getState(); if (release(savedState)) { failed = false; return savedState; } else { throw new IllegalMonitorStateException(); } } finally { if (failed) node.waitStatus = Node.CANCELLED; } }
这篇关于condition源码分析的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享