您好!欢迎来到爱源码

爱源码

热门搜索: 抖音快手短视频下载   

Java小白系列(十三):ReentrantLock 《互站网》

  • 时间:2022-07-18 00:20 编辑: 来源: 阅读:288
  • 扫一扫,手机访问
摘要:Java小白系列(十三):ReentrantLock 《互站网》
一、前言我们上次分析了AQS《小白十二》,重点分析了锁的获取和释放过程。AQS是一个普通的范畴。在本文中,我们将讨论AQS的子类:重入锁。 在我们正式谈论重新锁定之前,让我问几个小问题:为什么会有重新锁定?重新锁定使用场景?如果不重新入锁会怎么样?好了,带着这些问题,我们开始重新锁定的旅程吧。 二。不可重入锁(自实现)我在JDK没有找到不可重入锁的源代码,只好手动实现一个,看看不可重入锁的结果://不可重入lock.java公共类不可重入锁{private final原子引用< Thread & gtreference = new atomic reference & lt;& gt();public void lock(){ Thread Thread = Thread . currentthread();而(!reference.compareAndSet(空,线程));//CAS lock } public void unlock(){ thread thread = thread . current thread();而(!reference.compareAndSet(thread,null));// CAS unlock}}测试代码:公共类demo实现runnable { private non-reentrant lock = new non-reentrant lock();public static void main(String[]args){ new Thread(new Demo())。start();} @Override公共void run(){ int RES = fab(3);System.out.println("3!= "+RES);} private int fab(int n){ system . out . println(" Enter in fab ............... ");lock . lock();尝试{ if(n & lt;= 1){ return 1;} return n * fab(n-1);}最后{ lock . unlock();System.out.println("在fab中退出.........");}}}输出结果:输入fab............进入工厂............我们来分析一下造成这个结果的原因:第一次调用Fab方法(传入值3),输入并锁定;第二次调用fab方法(传入值为2 = 3-1),尝试锁,因为锁已经被持有,CAS只能原地等待;无法获得锁,无法继续执行;结果就是:死锁!同时还需要注意一点:Demo是同一个线程;同一个线程重复进入资源临界区;所以不可重入锁对任何线程都是一视同仁的,不管是同一个线程还是不同的线程,没有区别。那么,有递归的时候,就会出现死锁;上面的例子很简单,我们可以想办法避免。但是在实际开发中,我们很难保证同一个线程不会第二次进入资源的临界区而发生死锁。所以,这也是我开头提到的三个小问题的答案。 三。重入锁(自实现)锁通常是不同线程争夺同一资源的一种手段。但是,当同一个线程在已经持有锁的情况下重复进入同一个资源时,我们可以识别它,让它进入;然而,与此同时,我们还需要记录持有锁的线程的入口和出口数量。只有当入口和出口的数量完全相等时,最后一个出口才能真正释放锁。否则,也会出现死锁。 我们修改上面的例子,为了不影响前面的演示,我们新建一个类://canreentrantlock.java公共类canreentlock { private static final class lock object { thread thread = null;int count = 0;lock object(Thread Thread){ this . Thread = Thread;this . count = 1;} }私有最终AtomicReference & ltLockObject & gtreference = new atomic reference & lt;& gt();public void lock(){ Thread Thread = Thread . currentthread();lock object object = reference . get();if(object = = null){ object = new lock object(thread);而(!reference.compareAndSet(null,object));} else if(object . thread = = thread){ object . count++;reference.set(对象);} else { while(!reference.compareAndSet(null,new lock object(thread)));} } public void unlock(){ Thread Thread = Thread . currentthread();lock object object = reference . get();如果(反对!= null & amp& ampobject . thread = = thread){ object . count-;if (object.count == 0) { while(!reference.compareAndSet(object,null));}}}}修改我们的测试类:修改下面一行代码Private non retentrantlock = New non retentrantlock();替换为私有canreentrantlock lock = new canreentlock();但是我们再次执行了我们的测试用例,结果如下............进入工厂............进入工厂............在Fab中退出............在Fab中退出............在Fab中退出............3!= 6结果符合我们的预期!4.JDK的可重入锁ReentrantLock是JDK提供的可重入锁。它有一个内部静态通用类(Sync),继承自AQS;;同时,它有两个继承自Sync的静态实现类,即NonfairSync(不公平锁)和fairSync(公平锁)。 ReentrantLock是一种独占模式,因此,Sync及其子类需要实现三种方法:ISHELDEXCLUSIVE:根据被请求线程与当前持有线程的比较来判断是否需要独占,这就是重入机制(Sync实现);Try:释放锁(同步实现);TryAcquire:获取锁(这里公平和不公平是不一样的,后面会分析);4.1.构造函数公共类重入锁实现lock,Java . io . serializable { public reentrant lock(){ sync = newnonfairsync();} public ReentrantLock(布尔公平){ sync =公平?new FairSync():新的NonfairSync();}}默认构造函数使用不公平锁,我们也可以指定公平锁。 4.2.Fair lock (Fairsync)公共类reentrant lock实现lock,Java . io . serializable { static final class fair sync extends sync {/* * *回忆一下AQS获取锁的过程,再结合具体的子类,整个获取锁可以串起来:* lock->;获取-& gt;try acquire */final void lock(){ acquire(1);} protected final boolean try acquire(int acquires){ final Thread current = Thread . current Thread();//资源占用:0 =未被占用;1 = occupated int c = getState();if(c = = 0){//hasqueuedpredccessors判断CLH是否可以为空,体现了“公平性”特征。//如果CLH不为空,则它不会竞争锁,如果(!hasqueuedpredessors()& amp;& ampCompareandsetstate (0,acquisites)){//CLH为空,且CAS成功,将owner设置为当前线程setexclusiveownerthread(current);返回true} }//如果被占用,但是是自己的,则升级count else If(current = = getexclusiveownerthread()){ int nextc = c+acquisitions;if(nextc & lt;0)抛出新错误(“超过最大锁计数”);setState(nextc);返回true}返回false}}}公平锁比较简单。我们来看看不公平锁的实现。 4.3.不公平锁公共类reentrant lock实现lock,Java . io . serializable { static final class Unfair sync extends sync {//不公平锁,锁开始时CAS会先尝试一次,如果失败则调用acquir final void lock(){ if(compareandsetstate(0,1))setexclusiveownerthread(thread . current thread());否则获取(1);} //锁定失败-& gt;获取-& gt;tryAcquire受保护的最终布尔型try acquire(int acquires){ return nonfairTryAcquire(acquires);}}}就我们所见,在加入CLH之前,不公平锁尽可能利用“机会”试图收购锁:锁:第一次;TryAcquire:虽然我们看不到实现,但是从被调用的方法名可以看出“不公平重试”;4.3.1、Sync.nonfairTryAcquirepublic类ReentrantLock实现Lock,java.io.Serializable {抽象静态类Sync扩展AbstractQueuedSynchronizer {抽象void Lock();final boolean nonfairTryAcquire(int acquires){ final Thread current = Thread . current Thread();int c = getState();if(c = = 0){ if(compareAndSetState(0,acquisites)){ setExclusiveOwnerThread(current);返回true} } else if(current = = getExclusiveOwnerThread()){ int nextc = c+acquisites;if(nextc & lt;0) //溢出抛出新错误(“超过最大锁计数”);setState(nextc);返回true}返回false} .......}}请仔细比较一下FairSync.tryAcquire方法和Sync.nonfairTryAcquire方法,你会发现只有一行代码的区别:if (c == 0) {if(!hasqueuedpredessors()& amp;& amp//公平与不公平的唯一区别是compareandsetstate (0,acquisites)){ setexclusiveownerthread(current);返回true}}公平锁多了一个CLH的判断,CAS没有公平锁,而是试图再次获取锁,忽略了CLH。 4.4.静态内部通用类同步公共类重入锁实现lock,Java . io . serializable {抽象静态类同步扩展抽象队列同步器{抽象void lock());最终布尔型NonFairtryCQUIRE (IntAcquires) {...}//释放锁;确定是否可以重复重入,释放锁保护的最终布尔try release(int releases){ int c = getstate()-releases直到计数为0;if (Thread.currentThread()!= getExclusiveOwnerThread())抛出新的IllegalMonitorStateException();boolean free = falseif(c = = 0){ free = true;setExclusiveOwnerThread(null);} setState(c);免费退货;}//独占模式,判断是否可以:重新输入protected final boolean is heldexclusive(){ return getexclusiveownerthread()= = thread . current thread();} final condition object new condition(){ return new condition object();}最终线程getOwner() { return getState() == 0?null:getExclusiveOwnerThread();} final int getHoldCount(){ return is heldexclusive()?getState():0;}最终布尔isLocked() { return getState()!= 0;}}}五、总结正是由于我们对AQS获得和释放锁的过程进行了细致的分析;另外,我还用自己实现的一个例子来比较不重新锁定的后果;所以,我们学习ReentrantLock是非常容易的;至少ReentrantLock中的其他代码,只是setter/getter,不影响核心进程;由于锁的释放比较简单,我就不多分析了。你可以自己去看。


  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【技术支持|常见问题】1556原创ng8文章搜索页面不齐(2024-05-01 14:43)
【技术支持|常见问题】1502企业站群-多域名跳转-多模板切换(2024-04-09 12:19)
【技术支持|常见问题】1126完美滑屏版视频只能显示10个(2024-03-29 13:37)
【技术支持|常见问题】响应式自适应代码(2024-03-24 14:23)
【技术支持|常见问题】1126完美滑屏版百度未授权使用地图api怎么办(2024-03-15 07:21)
【技术支持|常见问题】如何集成阿里通信短信接口(2024-02-19 21:48)
【技术支持|常见问题】算命网微信支付宝产品名称年份在哪修改?风水姻缘合婚配对_公司起名占卜八字算命算财运查吉凶源码(2024-01-07 12:27)
【域名/主机/服务器|】帝国CMS安装(2023-08-20 11:31)
【技术支持|常见问题】通过HTTPs测试Mozilla DNS {免费源码}(2022-11-04 10:37)
【技术支持|常见问题】别告诉我你没看过邰方这两则有思想的创意广告! (2022-11-04 10:37)

联系我们
Q Q:375457086
Q Q:526665408
电话:0755-84666665
微信:15999668636
联系客服
企业客服1 企业客服2 联系客服
86-755-84666665
手机版
手机版
扫一扫进手机版
返回顶部