接着上一篇的
看一下ReentrantLock的源码,这里只是从AQS的角度出发,并不是从Lock的角度来看,那个以后再分析把
从AQS的状态角度,代码整体结构上是这样的:
//检查状态
while(!checkAndChangeState){
enque(currentthread) //将当前线程加入等待队列
park(currentThread) //挂起当前线程
}
//do sth
…….
//释放锁,恢复状态
changeState(){
Dequeue(current) //出对
Unpark(queue.thread)//唤醒其他等待中的线程
}
和真正的代码比起来主要是一些小地方的优化,比如一些自旋操作,特别是对于很小范围内的锁,另外,就是队列中的线程可能是已经取消的,这也要做相应的处理,下面就具体分析下
Lock的结构体系成对的主要有lock和unlock,其他方法到时候再看把:

我们看下lock方法:
public void lock() {
sync.lock();
}
//先暂且不管公平锁还是非公平锁,从独占锁的角度来说,就是请求一个状态
final void lock() {
acquire(1);
}
看下acquire的代码,完全就是上面伪代码的结构:
public final void acquire(int arg) {
//判断状态是否ok(自己实现),不ok的话就加入队列,并且阻塞(父类实现)
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
再来看下状态判断,这个是需要每个synchronizer自己做的:
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//这里初看起来会有并发问题,但是下面的cas操作保证了不会有并发问题,并且state字段是volatile的
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
//重入锁,单个线程内,不会有并发性的,所以直接set就好
setState(nextc);
return true;
}
return false;
}
这个方法如果返回true的话,代表条件允许,这样线程也就获得到锁了,其他啥也不用做了,等着释放锁,但是如果返回false,表示其他线程占用着,就需要加入等待队列,并且阻塞线程:
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
先看addWaiter:
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// 这里假设队列非空,并且没有太多的并发性,尝试快速入队
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//队列为空,或者存在高并发,入队的时候失败了,需要用while尝试入队
enq(node);
return node;
}
// 一个完整的入队操作,需要在一个循环里面判断队列是否为空、高并发等情况
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // 队列为空,需要初始化
Node h = new Node(); // Dummy header
h.next = node;
node.prev = h;
if (compareAndSetHead(h)) {//设置队列头,原子操作
tail = node;
return h;
}
}
else {// 队列非空,直接插到最后面
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
//在入队之后,在看下真正阻塞线程的acquireQueued,这里是一个循环操作,唤醒的时候也是重新去竞争,不是立刻获得锁
final boolean acquireQueued(final Node node, int arg) {
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
//在真正阻塞线程之前,如果发现自己前面的节点是head,那还要再尝试下去获取锁,获取到以后就把head踢了,自己当head,因为head的意义表示正在占用锁的节点(某些同步范围很短的锁很有用)
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return interrupted;
}
//该方法判断是否需要阻塞当前线程
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()) //park当前线程
interrupted = true; //默认不处理interrupted
}
} catch (RuntimeException ex) {
cancelAcquire(node); //发送异常的情况下,取消当前节点,并且如果当前节点是head,或者当前节点是等待唤醒状态,那么,还要尝试唤醒后面的节点
throw ex;
}
}
//决定是否需要阻塞当前线程
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int s = pred.waitStatus;
//如果当前节点的前一个节点的状态小于0(signal/condition),表示前面那个节点也在等待唤醒,果断把自己挂起
if (s < 0)
return true;
//如果前面节点的状态大于0,(cancelled),表示前面的线程已经取消,向前遍历,直到找到状态不大于0的节点
if (s > 0) {
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else
/*
* 前面一个节点的状态为0,那么就是前一个节点认为他后面没有节点需要唤醒 * 啦,这时候要果断把他的状态改为SIGNAL,因为SIGNAL状态表示后面有阻塞
线程需要唤醒.
*/
compareAndSetWaitStatus(pred, 0, Node.SIGNAL);
/**
在state>=0的情况下,会走到这里,这里不能返回true把自己挂起,
因为这时候线程切换,占用锁的线程A已经结束(并且发出了unpark信号),如果这时候线程B直接返回true阻塞自己,那可能会因为错失信号B永远无法唤醒;返回false,当前线程会去再次尝试获取锁,如果还是不能获取,则阻塞;
*/
return false;
}
//挂起当前线程,因为park会相应中断,但是不是抛出异常,因此这里将是否中断作为boolean类型返回,交给外部代码处理
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
//并不是只有unpark和interrupt才能唤醒他,参考前面的关于LockSupport的讲解;唤醒的线程,重新去竞争锁,在高并发的情况下,有可能另一个节点正好也在请求lock,那么他刚好tryAcquire成功了,则当前线程又会重新阻塞!
}
释放锁
/**
* 释放锁主要做下面两件事情:
* 1.修改状态,改为可以获取锁
* 2.如果有等待的线程,则唤醒一个
*/
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
//如果waitStatus为0,则表示后面没阻塞线程了,没必要进行唤醒了
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
//先看修改状态的方法,这里只修改锁的状态,不修改队列的任何东西
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
//进行唤醒操作
private void unparkSuccessor(Node node) {
/*
* 把自己状态改为0,表示后面没有节点需要唤醒;如果后面有需要唤醒的节点,在请求锁的时候会把他的状态改为SIGNAL,不是很明白为什么这么做,难道是一种小小的优化?
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
//取队列里面状态不大于0(cancelled)的节点,如果大于0,则从队列移除,然后从后往前找,找到最前面的一个非cancelled节点,并且唤醒这个节点
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}
总结
1.通过AQS的state字段来表示锁是否被占用,特别需要注意的就是他的操作都是原子的
2.通过队列来保存阻塞的线程
3.通过LockSupport来进行挂起和唤醒操作(LockSupport的注意点可以看上一篇)
从挂起的时机上,AQS加了一些自旋操作,不是每次发现不能获取锁就挂起,而是后来会再次尝试获取锁,这样,对那些同步范围非常小,时间非常短的锁,应该是一种性能的提高。
另外,对于队列的操作,从我个人的角度来看,每次取当前正在跑的节点,跑完以后再取下一个节点,如果是取消状态,那么再去下一个,最后找到一个ok的唤醒,这样就可以了。不过AQS增加了一些状态判断,比如通过waitStatus来判断后面是否有节点需要唤醒,从角度来看,这完全增加了成本,不过性能提高多少就难说喽!
相关推荐
内容概要:本文详细介绍了如何利用COMSOL软件复现超表面的多种物理特性,特别是Qbic技术的应用。主要内容涵盖超表面的结构与透射谱、偏振变化透射谱、结构变化透射谱、法诺曲线拟合、BIC位置Q因子计算、多级子分解及电场磁场模式图等方面。通过这些技术手段,可以深入了解超表面的光学响应和物理特性,为设计和优化超表面提供理论支持和技术指导。 适合人群:从事超表面研究的科研人员、物理学专业学生、光学工程领域的研究人员。 使用场景及目标:适用于希望深入了解超表面物理特性的科研工作者,旨在帮助他们掌握COMSOL软件的具体操作技巧,提高超表面设计和优化的能力。 其他说明:文中还附有MATLAB代码片段,用于展示如何在COMSOL中进行超表面的建模和仿真。
通信线路施工安全生产事故预案.doc
内容概要:本文详细介绍了利用MATLAB进行变压器剩磁计算的方法及其重要性。首先解释了剩磁的概念,它是变压器断电后铁芯材料中残留的磁场。接着展示了如何在MATLAB中定义磁通波形参数并通过数值积分等方式计算剩磁值。最后,通过MATLAB的绘图功能展示了磁通波形变化及剩磁值的计算结果。文中还强调了剩磁值对于评估变压器性能和安全性的重要性。 适合人群:电气工程专业学生、从事电力设备研究的技术人员、对变压器特性感兴趣的科研工作者。 使用场景及目标:适用于需要评估变压器性能和安全性的场合,特别是涉及剩磁对变压器影响的研究项目。目标是提高对变压器剩磁现象的理解,优化变压器的设计和维护。 其他说明:文中提供的MATLAB代码片段可以作为初学者入门的基础,进一步深入时可根据实际情况调整和完善代码。
内容概要:本文详细探讨了在连续介质中束缚态驱动下的平面手征超表面的最大和可调谐手征光学响应。研究利用Comsol Multiphysics软件进行仿真分析,重点考察了三次谐波、本征手性BIC(Bound States in the Continuum)、远场偏振图、手性透射曲线、二维能带图、Q因子图以及电场图等关键技术指标。通过调整模型参数,如材料属性和结构尺寸,研究人员成功模拟并分析了不同光学响应的现象,揭示了超表面在特定条件下的独特光学行为。 适用人群:适用于从事光学、物理学及相关领域的科研人员和技术专家,尤其是那些对超表面和光与物质相互作用感兴趣的学者。 使用场景及目标:①帮助研究人员深入了解平面手征超表面的工作机制;②提供详细的仿真分析方法,便于后续实验设计和理论验证;③为开发新型光学器件和材料提供理论支持和技术指导。 其他说明:文中还涉及与其他研究者的成果对比,旨在验证当前研究方法的有效性和可靠性,并提出改进建议,以提升超表面的光学性能和稳定性。
内容概要:本文详细探讨了线控转向系统在失效情况下的容错差动转向控制策略。线控转向系统以其精准控制和快速响应的优势被广泛应用,但也面临系统失效的风险。文中介绍了容错差动转向控制的理念,即在某一侧转向执行器失效时,通过调整另一侧的转向角来维持车辆的基本转向能力。具体实现了故障检测与诊断以及转向角分配策略,并讨论了系统稳定性和安全性问题。最后,提出了未来改进的方向和技术挑战。 适合人群:从事汽车工程、自动驾驶技术研发的专业人士,尤其是关注线控转向系统及其容错机制的研究人员。 使用场景及目标:适用于希望深入了解线控转向系统失效应对措施的技术专家,旨在提升车辆在极端条件下的安全性和可靠性。 其他说明:文中不仅提供了理论分析,还附有具体的代码示例,便于读者理解和实践。此外,强调了系统实时性和用户反馈机制的重要性,指出了未来研究的关键点。
内容概要:本文详细介绍了两电平逆变器在MATLAB 2021a环境下的SPWM(正弦脉宽调制)技术和LCL滤波器的应用,旨在实现对称三相电压电流波形及三电平输出效果。首先阐述了SPWM的工作原理,即通过调整脉冲宽度来模拟正弦波,进而精确控制逆变器的开关时刻。接着讨论了LCL滤波器的作用,它能够有效减少输出电压和电流的谐波成分,提升波形质量。最后,通过合理设计SPWM控制策略和LCL滤波器参数,实现了三电平输出,提高了系统的效率和稳定性。文中还提供了部分MATLAB代码片段用于演示SPWM控制算法。 适用人群:从事电力电子技术研究的专业人士、高校师生及相关领域的研究人员。 使用场景及目标:适用于需要深入了解两电平逆变器工作原理和技术细节的人群,帮助他们掌握SPWM调制技术和LCL滤波器的设计方法,以便应用于实际项目中,如新能源发电、工业自动化等领域。 其他说明:本文不仅提供了理论分析,还有具体的仿真实验指导,有助于读者更好地理解和实践两电平逆变器的相关技术。
透析工程项目管理七种模式及其特点.doc
内容概要:本文详细介绍了锂离子电池热失控模型的参数辨识方法,特别是基于加速量热法(ARC)测试数据的一方程模型参数辨识。文中涵盖了热失控现象的背景与意义、ARC测试数据的获取方式、MATLAB软件的具体应用步骤,包括数据导入、模型建立、参数优化及最终的仿真验证。通过这种方法,研究人员可以获得高精度的热失控模型参数,进而更好地理解和预测锂离子电池的热失控行为。 适合人群:从事电池安全研究的专业人士、科研工作者、高校师生及相关领域的工程师。 使用场景及目标:适用于需要深入了解锂离子电池热失控机理的研究项目,旨在提高电池安全性设计和预防热失控事故的发生。 其他说明:本文侧重于参数辨识的技术细节,未涉及具体的 Fluent 软件仿真设置,但提供了相关书籍和文献供进一步学习。
内容概要:本文详细介绍了一维纳米光栅的能带计算及其相关处理方法。首先,在Comsol Multiphysics中建立了纳米光栅模型,设定了材料参数、尺寸和周期等关键属性。接着,通过求解麦克斯韦方程计算了能带结构,并针对可能出现的伪模进行了处理,确保仿真结果的准确性。最后,通过设定色散关系和边界条件,实现了波长频率与波矢间关系的复现。文中还附有详细的代码示例,帮助读者更好地理解和应用这些技术。 适合人群:从事光子学研究、光学仿真及相关领域的科研人员和技术开发者。 使用场景及目标:适用于需要精确模拟和分析一维纳米光栅光学特性的场合,旨在提升对光栅光学性质的理解和优化能力。 其他说明:这些技术不仅有助于深入理解光栅的工作机制,还在光子学、光学通信和光学传感器等领域有着广泛的应用前景。
内容概要:本文详细解析了计算机网络中的三个核心概念——IP地址、子网掩码和默认网关。首先介绍了IP地址作为网络设备唯一标识的作用及其分类,包括IPv4地址的结构与五类地址的应用场景,特别是私有地址的特殊用途。接着阐述了子网掩码的功能,即通过按位与运算区分IP地址中的网络部分和主机部分,实现子网划分,并介绍了基于子网数量或主机数量的划分方法及CIDR表示法。最后讲解了默认网关作为跨子网通信桥梁的重要性,描述了其配置方法和常见问题,以及三者协同工作的具体实例。; 适合人群:对计算机网络基础知识有一定了解的技术人员或网络管理员,希望深入了解IP地址、子网掩码和默认网关的工作原理。; 使用场景及目标:①掌握IP地址分类及其在网络中的作用;②学会使用子网掩码进行网络划分;③理解默认网关在跨子网通信中的角色,确保网络配置正确无误。; 其他说明:通过对这三个核心概念的深入理解,可以优化网络性能,提高网络设计的灵活性与可靠性,为复杂的网络环境提供坚实的理论基础。建议读者结合实际网络环境进行配置实践,以加深理解并解决实际问题。
综合布线系统的设计施工测试验收和维护培训.ppt
【数据集详情】data目录下分为2个目录,train为训练集、val为验证集,存放各自的同一类数据图片。train数据总数1100,val数据总数50。可以用作yolov5的分类数据集。为了方便查看数据,提供了可视化py文件,随机传入4张图片即可展示,并且保存在当前目录。 关于神经网络改进:https://blog.csdn.net/qq_44886601/category_12858320.html 类别10: "{ "0": "almonds", "1": "brazil nuts", "2": "cashews", "3": "coconut", "4": "hazelnuts", "5": "macadamia", "6": "pecans", "7": "pine nuts", "8": "pistachios", "9": "walnuts" }
内容概要:本文详细介绍了基于200smart PLC的135恒压供水系统的设计与实现。系统采用子程序方式编写,涵盖模拟量转换、PID控制和模式切换控制等关键技术。通过内置AD转换模块,将压力传感器的电压信号转换为数字信号,确保水压的精确控制。PID控制器用于调节输出值,使其跟随设定的目标水压。此外,系统支持多种工作模式的切换,以适应不同应用场景。昆仑通泰的触摸屏提供了友好的人机交互界面,便于用户进行参数设置和系统监控。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是对PLC编程和恒压供水系统感兴趣的读者。 使用场景及目标:适用于需要理解和掌握200smart PLC编程技巧、模拟量转换、PID控制及模式切换控制的应用场景。目标是提高系统的稳定性和可靠性,提升用户的操作体验。 其他说明:文中提供的代码示例有助于读者更好地理解程序逻辑,同时强调了实际应用中的调试和优化步骤。
1. 用户管理模块 用户注册与登录:支持邮箱 / 手机号注册,提供密码找回和重置功能 第三方登录:集成微信、QQ、微博等第三方登录方式 用户信息管理:个人资料编辑、头像上传、个性签名设置 隐私设置:控制个人音乐喜好、播放历史的公开程度 用户社交关系:关注其他用户、查看关注列表和粉丝列表 2. 音乐资源管理模块 歌曲管理:歌曲信息录入、分类、标签管理 艺术家管理:艺术家信息录入、专辑管理 歌单管理:支持用户创建、编辑和分享歌单 音乐分类:按风格(流行、摇滚、古典等)、语言、年代等分类 音乐上传与审核:支持音乐人上传作品,管理员审核机制 3. 音乐播放模块 音乐播放控制:播放、暂停、上一首、下一首、音量调节 播放模式:单曲循环、列表循环、随机播放 歌词显示:同步显示歌词,支持歌词滚动和字体调整 播放历史记录:记录用户播放过的音乐 音乐收藏:支持收藏歌曲、艺术家和歌单 4. 协同过滤推荐模块 基于用户的协同过滤:根据用户相似度推荐音乐 基于物品的协同过滤:根据音乐相似度推荐音乐 混合协同过滤:结合用户和物品协同过滤的优点 推荐结果展示:个性化推荐歌单、每日推荐、相似音乐推荐 推荐算法优化:不断优化算法,提高推荐准确率 5. 用户交互与社交模块 音乐评论:用户可对歌曲、专辑和歌单发表评论 点赞与分享:支持对音乐内容点赞和分享到社交平台 音乐动态:发布音乐相关的动态、心情和感悟 私信功能:用户间可以发送私信交流音乐心得 音乐社区:讨论音乐话题、分享音乐资源的社区板块 6. 个性化设置模块 音乐偏好设置:设置喜欢的音乐风格、艺术家和歌曲 推荐权重调整:调整不同推荐算法的权重 界面主题设置:支持多种主题风格切换 通知设置:自定义接收通知的类型和方式 7. 数据分析与日志模块 用户行为分析:分析用户的播放历史、收藏行为等 音乐热度分析:统计歌曲、艺术家的播放量和收藏量 推荐效果分析:评估推
内容概要:本文详细探讨了Comsol相场法在模拟裂纹力学行为和多孔介质水力压裂中的应用。首先介绍了单边裂纹在剪切载荷和拉伸载荷作用下的行为特征,通过设置不同的边界条件和材料属性,展示了裂纹扩展的具体过程。接着讨论了在初始地应力场作用下,多孔介质中水力压裂的复杂过程,强调了多物理场耦合的影响。最后指出Comsol相场法在模拟裂纹行为方面的高精度和灵活性,为工程实践提供了重要的理论支持和技术手段。 适合人群:从事岩土工程、地质力学、石油工程等相关领域的研究人员和工程师。 使用场景及目标:适用于需要精确模拟裂纹扩展和水力压裂的研究项目,帮助理解和预测裂纹在不同载荷条件下的行为,优化工程设计方案。 其他说明:文中引用了多个相关参考文献,进一步丰富了研究背景和理论依据。
摘 要 I 1 绪论 1 1.1研究背景 1 1.2研究现状 1 1.3研究内容 2 2 系统关键技术 3 2.1 Spring Boot框架 3 2.2 JAVA技术 3 2.3 MYSQL数据库 4 2.4 B/S结构 4 3 系统分析 5 3.1 可行性分析 5 3.1.1 技术可行性 5 3.1.2经济可行性 5 3.1.3操作可行性 5 3.2 系统性能分析 5 3.3 系统功能分析 6 3.4系统流程分析 7 3.4.1登录流程 7 3.4.2注册流程 8 3.4.3添加信息流程 8 3.4.4删除信息流程 9 4 系统设计 10 4.1系统概要设计 10 4.2系统结构设计 10 4.3系统顺序图设计 11 4.3.1登录模块顺序图 11 4.3.2添加信息模块顺序图 11 4.4数据库设计 12 4.4.1数据库E-R图设计 12 4.4.2数据库表设计 13 第5章 系统详细设计 17 5.1前台首页功能模块 17 5.2管理员功能模块 18 5.3学生功能模块 21 6 系统测试 24 6.1 测试定义 24 6.2 测试目的 24 6.3测试方案 25 (1)模块测试 25 (2)集成测试: 25 (3)验收测试: 25 6.4系统分析 27 7 结论 28 参考文献 29 谢辞 30
华为OD机试C++-字符串加密.html
软件与专业服务市场.ppt
内容概要:本文详细介绍了基于Lattice规划算法和MPC(模型预测控制)的路径规划与跟踪控制技术。首先探讨了Lattice规划算法作为先进路径规划方法的应用,特别是在智能交通系统中的优势,如提高交通效率、降低拥堵和事故风险。接着阐述了MPC在路径跟踪控制中的作用,通过实时环境建模和预测,确保车辆能灵活应对复杂的交通状况。文中通过Simulink文件和Carsim cpr文件展示了这两种技术的具体实现过程,并提供了视频和图片展示,直观呈现了路径规划和跟踪的效果及其相关变量的变化情况。 适合人群:从事自动驾驶、智能交通系统研究的专业人士和技术爱好者。 使用场景及目标:适用于希望深入理解Lattice规划算法和MPC在路径规划与跟踪控制中的具体应用的研究人员和工程师。目标是提升对这两项技术的理解,促进其在实际项目中的应用和发展。 其他说明:文章不仅提供了理论解释,还有丰富的视觉材料辅助理解,使读者可以更直观地掌握这些先进技术的实际效果。
车机-虚拟音量键app-debug