我们知道,java.util.concurrent.locks包下的Lock和Condition接口的语义是用来替代JDK1.5之前使用synchronize和Object.wait、Object.notify、Object.notifyAll组合,Effective Java一书中说过,JDK1.5及其以后,你几乎没有任何理由去选择使用synchronize和Object.wait、Object.notify、Object.notifyAll组合,除非是为了维护之前的代码。
除了Lock和Condition这两个接口,和锁相关的还有读写锁ReadWriteLock接口,这个会单独介绍,本文关注的是Lock和Condition。
我们先看看Lock接口的定义:
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
可以看出,与synchronize相比,Lock的语义更加丰富,synchronize和Lock(的实现)都是可重入,但synchronize不会响应中断信号,也不能做到限时等待,它只会干等、无线等,这无法满足某些场景下的需求,所以,在你希望做到可中断等、可中断限时等、尝试获取锁时,你该考虑使用Lock的实现。
可重入锁ReentrantLock是Lock接口的直接实现,它也借助了AQS(关于AQS介绍,可以参考另一篇博文:http://manzhizhen.iteye.com/blog/2305890),我们接下来还是先从Sync说起,和信号量Semaphore(可以参考另一篇博文:http://manzhizhen.iteye.com/blog/2307298)一样,Sync是ReentrantLock中实现了AQS的内部类,我们这里先给出Sync的实现:
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
// 之所以这里没有实现关键的lock操作,是因为不同的策略(公平和非公平)有不同的lock方式
abstract void lock();
/** 看名字就知道是非公平策略下尝试获取锁所调用的操作 */
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// c==0表明现在还没有线程来获取这把锁
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");
// 再次获取锁的许可,这里需要将许可数添加到state中
setState(nextc);
return true;
}
return false;
}
/** 无需多说,释放锁的通用操作*/
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 如果此时state值为0,说明此时该线程已经和该锁脱离关系了,所以锁的拥有者得设置成null
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
/** 判断当前线程是否是获取该锁的线程*/
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
/** 返回锁的拥有者线程*/
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
/** 当前线程持有该锁的次数*/
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
/** 当state为0,表明已经没有线程持有该锁*/
final boolean isLocked() {
return getState() != 0;
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
从ReentrantLock的Sync的实现来看,我们得到两个重要信息:1.只能有一个线程拥有该锁,所以ReentrantLock是使用AQS的独占模式。2.锁可以被拥有者线程重复持有,即可重入,并用AQS中state来记录拥有者线程当前持有该锁的次数,tryAcquire一次则state+1,tryRelease一次则state-1,所以当state为0时,表明该锁目前没有被任何线程持有。
我们已经知道,像信号量Semaphore一样,ReentrantLock对于资源的抢占机制也有两种:公平和非公平,在ReentrantLock中,也是在创建ReentrantLock对象时就决定的,运行期间不可修改,默认是非公平的,我们看下ReentrantLock的构造方法:
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
这段代码和信号量Semaphore的构造函数几乎一模一样,所以,很显然FairSync代表公平策略的实现,而NonfairSync代表非公平的实现,而且FairSync和NonfairSync都继承于上面提到的Sync。
从NonfairSync的实现,我们可以看出,在ReentrantLock的实现中,当AQS的state为0时,表示锁没有被线程使用,一旦有线程成功将state修改成1,则该线程则成为锁的拥有者,其他线程只要等state重新变成0时,才有机会去重新尝试占有该锁。锁的拥有者线程可以重复获取该锁,每获取一次,state都会加1,每释放一次,state都会减1,知道最终state重新变成0,即拥有者线程彻底放弃该锁。
我们先来看看默认的非公平NonfairSync的实现:
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
可以看出,有了Sync,NonfairSync变得异常简单,它实现了Sync中没有实现的lock方法,lock方法会先看state值是否为0,为0表明该锁还没被线程拥有,所以立马将其设为1(是个CAS过程),如果成功,则把当前线程设置成独占锁的拥有者,如果失败或者state根本不为0,则说明当前线程可能没有抢锁成功或者当前线程不是第一次持有该锁了(可重入性),此时则会调用AQS的独占获取资源的方法acquire(acquire(1);),在AQS的博文中我提到过,对于独占访问,实现类只需要提供tryAcquire方法的实现即可,至于独占获取资源中的获取资源尝试、排队等待等相关操作都是AQS提供的,这里还是给出AQS中acquire的代码:
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
在这里,acquire先会调用我们自己tryAcquire方法的实现,如果获取资源数成功,则返回,否则则以独占的方式进入队列中等待,而我们NonfairSync实现的tryAcquire方法是直接调用Sync中的nonfairTryAcquire实现,上面已经给出了代码和注释,这里不再解释。还记得上面说过的Lock接口中定义的lock方法吗?Sync中定义的lock操作就是为其准备的,我们看看ReentrantLock中的lock实现就知道了:
public void lock() {
sync.lock();
}
虽然API上说Lock接口的lock语义是阻塞的,但我们知道,ReentrantLock的锁是独占的,如果是锁的拥有者,自然可以重复获取锁而不需要等待,如果不是锁的拥有者,则只能乖乖的进入AQS的队列中,只有当state为0时,队列中线程才有机会。tryAcquire方法是是使用AQS独占模式必须实现的方法,在NonfairSync中它是直接调用Sync的nonfairTryAcquire实现。
我们再来看看公平的FairSync的内部实现:
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// 对于公平策略,当state为0时,不能直接去尝试作为锁的拥有者,因为有可能队列中还有线程在等
if (c == 0) {
// 如果队列中没有线程且将state由0设置成1成功,则说明已经成功拥有该锁
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
// 拥有该锁后,将拥有者线程设置成当前线程
setExclusiveOwnerThread(current);
return true;
}
}
// 当前线程本来就是锁的拥有者,则直接给state值+1
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
// 这里之所有没有用CAS操作给state设值,是因为当锁找到拥有者后,只有拥有者线程能修改state
setState(nextc);
return true;
}
return false;
}
}
和NonfairSync中的lock方法相比,FairSync的lock是直接调用AQS中的acquire操作,而没有经过compareAndSetState(0, 1)的CAS操作,因为对于公平策略来说,即使这时碰巧锁的拥有者放弃了锁的使用权,它也不能通过CAS操作尝试去获取该锁,因为有可能AQS的队列中还有线程同样也在等待这个机会,所以不能直接让它走NonfairSync的lock中的CAS这一步。因为AQS中的acquire方法会先调用tryAcquire,所以在tryAcquire不能光去看state是否为0,即使state为0当前线程也不能去尝试拥有该锁,所以tryAcquire还通过调用AQS中的hasQueuedPredecessors方法来看队列中是否有排队线程,如果没有,才去使用CAS来尝试获取该锁(compareAndSetState(0, acquires)),当此线程在此时队列中没有等待线程却还争夺锁失败或者当此线程不是锁的拥有者线程时,tryAcquire会返回false,于是AQS的acquireQueued操作直接让它去排队了(acquireQueued(addWaiter(Node.EXCLUSIVE), arg))),排队的这部分操作在AQS的博文中有简单描述,这里不再重复。
到目前为止,获取锁的公平和非公平策略都描述完了,释放锁的通用操作在Sync部分已经通过tryRelease实现,所以对于公平和非公平的策略,释放锁的步骤是一样的。关于锁,我们还剩一个话题,就是条件Condition!
我们直接看ReentrantLock内部的newCondition操作的实现:
public Condition newCondition() {
return sync.newCondition();
}
可见,它直接调用了Sync中的newCondition,这部分代码已经在前面给出,它直接新建了一个AQS中的条件对象ConditionObject返回了,所以ReentrantLock中的条件完全依赖了AQS中条件的实现,我在AQS中的博文已经阐述这里我们也不再多说。
ReentrantLock的核心操作就描述到这里。
相关推荐
项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行,功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用
内容概要:本文档提供了关于数据分析全面的知识介绍与实战资源链接。首先,在数据分析的基础教程部分讲述了使用Python以及R两种语言来进行实际的数据分析工作所需具备的各项基本技能。其次,进阶教程涵盖从机器学习到深度学习的概念及其Python具体应用场景。接着,在工具有效利用层面介绍了多种热门库与平台的作用特点。在项目实践中,列举了四个实战案例:Titanic幸存者预测、房价预测、社交媒体情感倾向分析以及市场顾客购买模式研究,每个项目都有详细的技术流程指引。另外列出多个外部网站资源供进一步提升学习。 适用人群:本文主要面向有志于从事数据挖掘工作的学生和技术爱好者,同时也可辅助在职人士自我能力进阶。无论是在学术科研还是实际业务需求环境中都值得研读。 使用场景及目标:学习者将能够获取到系统的理论知识体系,熟悉业界主流软件包的功能优势,掌握具体业务问题解决方案路径,提高自身的综合技术素质,从而为个人职业规划增添竞争力。 其他说明:文档里推荐了不少高质量参考资料和实用线上学习社区,能有效补充专业知识空白并促进社交协作交流。
从埃安泰国工厂竣工看中国车企加快海外建厂步伐.pptx
复现改进的L-SHADE差分进化算法求解最优化问题详解:附MATLAB源码与测试函数集,复现改进的L-SHADE差分进化算法求解最优化问题详解:MATLAB源码与测试集全攻略,复现改进的L-SHADE差分进化算法求最优化问题 对配套文献所提出的改进的L-SHADE差分进化算法求解最优化问题的的复现,提供完整MATLAB源代码和测试函数集,到手可运行,运行效果如图2所示。 代码所用测试函数集与文献相同:对CEC2014最优化测试函数集中的全部30个函数进行了测试验证,运行结果与文献一致。 ,复现; 改进的L-SHADE差分进化算法; 最优化问题求解; MATLAB源代码; 测试函数集; CEC2014最优化测试函数集,复现改进L-SHADE算法:最优化问题的MATLAB求解与验证
可选择参考电压与输出电压 可选择电阻精度以及输出电压误差值
西门子博途三部十层电梯程序案例解析:基于Wincc RT Professional V14及更高版本的应用探索,西门子博途三部十层电梯程序案例解析:基于Wincc RT Professional画面与V14及以上版本技术参考,西门子1200博途三部十层电梯程序案例,加Wincc RT Professional画面三部十层电梯程序,版本V14及以上。 程序仅限于参考资料使用。 ,西门子;1200博途;三部十层电梯程序案例;Wincc RT Professional;V14以上程序版本。,西门子V14+博途三部十层电梯程序案例:Wincc RT Pro专业画面技术解析
2023政务大数据解决方案.pptx
项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行;功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用
内容概要:本文介绍了基于Java的学业跟踪评价系统的详细设计与实现,涵盖系统的多维度数据整合与评价、智能化学习建议、数据可视化和实时反馈等方面。系统通过收集课堂表现、作业成绩、考试成绩等多源数据,对学生的学业表现进行全面跟踪和评价,提供可视化反馈以及个性化的学习建议,促进家校互动,助力学生全面素质提升和发展。 适合人群:具备一定Java编程经验的研究者和开发者,特别是从事教育信息化领域的从业人员和技术爱好者。 使用场景及目标:该系统主要用于K12教育阶段、高等教育以及其他涉及教育培训的场景。其目的是提高教育管理效率、推进教育数字化转型和个人化教育实施。 其他说明:该文档详细介绍了系统的设计思路、功能模块和技术细节,并提供了完整的程序代码以及GUI设计说明。对于希望深入了解或实际部署学业跟踪评价系统的机构非常有参考价值。文中强调技术创新与实践经验相结合,突出了实用性和前瞻性特点。
项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行;功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用
erlang安装包,rabbmit安装环境
linux 下的oracle数据库的开机启动脚本,将里面的/home/oracle/app/oracle/product/11.2.0/dbhome_1 都改成你的oracle数据库的路径。在root用户下chmod +x 添加执行权限,然后./oracle_setup.sh 执行即可。
基于目标级联分析法的多微网主动配电系统自治优化经济调度算法实现与初级应用,基于目标级联分析法的多微网主动配电系统自治优化经济调度算法实践:初级拉格朗日算法应用,GAMS代码:基于目标级联分析法的多微网主动配电系统自治优化经济调度 该代码并非完全复现该文献,而是参照文献 《基于目标级联分析法的多微网主动配电系统自治优化经济调度》 的目标级联分析法(ATC)的算法部分,采用初级的拉格朗日算法,主网与配网部分模型较为简化。 代码结构完整,注释详细,可读性较强,可以在此基础上进行修改或者移植。 适用于初学者学习ATC模型 ,GAMS代码;目标级联分析法(ATC);微网主动配电系统;自治优化经济调度;拉格朗日算法;主网与配网模型简化;代码结构完整;注释详细;可读性强;初学者学习ATC模型。,基于ATC算法的GAMS多微网经济调度优化代码:简化版学习指南
基于ISODATA改进算法的负荷场景曲线聚类——适用于风光场景生成的高效算法创新,基于ISODATA改进算法的负荷场景曲线聚类(适用于风光场景生成,包含K-means等多种聚类方法与效果评价),基于ISODATA改进算法的负荷场景曲线聚类(适用于风光场景生成) 摘要:代码主要做的是一种基于改进ISODATA算法的负荷场景曲线聚类,代码中,主要做了四种聚类算法,包括基础的K-means算法、ISODATA算法、L-ISODATA算法以及K-L-ISODATA算法,并且包含了对聚类场景以及聚类效果的评价,通过DBI的计算值综合对比评价不同方法的聚类效果,程序实现效果非常好,适合对于算法创新有需求的人,且也包含基础的k-means算法,用来学习也非常棒 另外,此代码同样适用于风光场景生成,自己准备好风光场景数据即可 代码非常精品,有部分注释; ,核心关键词: 1. 基于ISODATA改进算法 2. 负荷场景曲线聚类 3. K-means算法 4. 聚类场景评价 5. 聚类效果评价 6. DBI计算值 7. 算法创新需求 8. 风光场景生成 以上关键词用分号分隔为: 1. 基于ISO
xPack qemu arm 是一款高性能且跨平台的 ARM 架构虚拟机
莫理莉+AI+为新型能源系统赋能-技术与建筑建筑供配电论坛琶洲.pptx
学生毕业离校系统(源码+数据库+论文+ppt)java开发springboot框架javaweb,可做计算机毕业设计或课程设计 【功能需求】 本系统分为学生、教师、管理员3个角色 (1)学生功能需求 学生进入系统可以查看首页、个人中心、离校流程、网站公告、费用结算管理、论文审核管理、我的收藏管理等操作。 (2)教师功能需求 教师进入系统可以查看首页、学生管理、离校流程管理、费用结算管理、论文审核管理等操作。 (2)管理员功能需求 管理员登陆后,主要功能模块包括首页、个人中心、学生管理、教师管理、离校信息管理、费用结算管理、论文审核管理、管理员管理、留言板管理、系统管理等功能。 【环境需要】 1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境:IDEA,Eclipse,Myeclipse都可以。 3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可 4.数据库:MySql 5.7/8.0等版本均可; 【购买须知】 本源码项目经过严格的调试,项目已确保无误,可直接用于课程实训或毕业设计提交。里面都有配套的运行环境软件,讲解视频,部署视频教程,一应俱全,可以自己按照教程导入运行。附有论文参考,使学习者能够快速掌握系统设计和实现的核心技术。
揭秘 OpenAI 在 2027 年前创建 AGI 的计划.pptx
单极双极调制下,线路阻抗不匹配时两台单相逆变器并联的离散仿真模型研究,单极双极调制下,线路阻抗不匹配时单相逆变器Simulink并联仿真模型研究,单相逆变器Simulink并联离散仿真模型,输入电压400V,单台逆变器功率为2000W,使用下垂控制方案,在线路阻抗不匹配的情况下,实现两台逆变器并联。 可以选调制方案为单极性调制或者双极性调制。 离散模型,功率均分效果,两台逆变器输出电压和电流波形如下图。 ,核心关键词:单相逆变器; Simulink; 并联离散仿真模型; 输入电压400V; 单台功率2000W; 下垂控制方案; 线路阻抗不匹配; 调制方案; 单极性调制; 双极性调制; 功率均分效果。,离散仿真模型下,单相逆变器并联研究——400V输入、2000W功率均分实现
基于PLC的双层自动门控制:光电传感触发,有序开关与延时功能实现,附程序、画面及参考文档。,基于PLC的双层自动门控制系统:精准控制,保障无尘环境;门间联动,智能安防新体验。,基于plc的双层自动门控制系统,全部采用博途仿真完成,提供程序,画面,参考文档,详情见图。 实现功能(详见上方演示视频): ① 某房间要求尽可能地保持无尘,在通道上设置了两道电动门,门1和门2,可通过光电传感器自动完成门的打开和关闭。 门1和门2 不能同时打开。 ② 第 1 道门(根据出入方向不同,可能是门 1 或门 2),是由在通道外的开门者通过按开门按钮打开的,而第 2 道门(根据出入方向不同,可能是门 1 或门 2 )则是在打开的第 1 道门关闭后自动地打开的(也可以由通道内的人按开门按钮来打开第2 道门)。 这两道门都是在门开后,经过 3s 的延时而自动关闭的。 ③ 在门关闭期间,如果对应的光电传感器的信号被遮断,则门立即自动打开。 如果在门外或者在门内的开门者按对应的开门按钮时,立即打开。 ④ 出于安全方面的考虑,如果在通道内的某个人经过光电传感器时,对应的门已经打开,则通道外的开门者可以不按开门按钮。