谈谈你对可重入锁和不可重入锁的理解、区别及原理

news/2024/7/19 14:41:27 标签: 多线程, 并发编程, http, 编程语言, js
js_content">

点击上方“果汁简历”,选择“置顶公众号”

首先我们这里提到的锁,是把所需要的代码块,资源,或数据锁上,在操作他们的时候只允许一个线程去做操作。最终结果是为了保证cpu计算结果的正确性。

对不可重入锁的理解:

public class Test{
     Lock lock = new Lock();
     public void methodA(){
         lock.lock();
         ...........;
         methodB();
         ...........;
         lock.unlock();
     }
     public void methodB(){
         lock.lock();
         ...........;
         lock.unlock();
     }
}

当A方法获取lock锁去锁住一段需要做原子性操作的B方法时,如果这段B方法又需要锁去做原子性操作,那么A方法就必定要与B方法出现死锁。这种会出现问题的重入一把锁的情况,叫不可重入锁。

A方法需要等B方法执行完才能解锁,但是B方法想执行完代码又必须要lock锁来加锁。A的锁未解锁前,其他代码块无法使用此锁来加锁。这是由这个不可重入锁决定的。

不可重入锁:

public class Lock{
     private boolean isLocked = false;
     public synchronized void lock() throws InterruptedException{
         while(isLocked){    
             wait();
         }
         isLocked = true;
     }
     public synchronized void unlock(){
         isLocked = false;
         notify();
    }
}

那么平时我们又有需要重入一把锁的需求!!!!比如A方法是个原子性操作,但它有需要调用B方法的原子性操作,他们还争抢的是同一个临界资源,因此需要同一把锁来加锁(ps:争抢同一临界资源的实质就是对同一把锁的争抢)

针对此情况,就有了可重入锁的概念:

可重入锁的实现:

public class Lock{
    boolean isLocked = false;
    Thread  lockedBy = null;
    int lockedCount = 0;
    public synchronized void lock()
            throws InterruptedException{
        Thread thread = Thread.currentThread();
        while(isLocked && lockedBy != thread){
            wait();
        }
        isLocked = true;
        lockedCount++;
        lockedBy = thread;
    }
    public synchronized void unlock(){
        if(Thread.currentThread() == this.lockedBy){
            lockedCount--;
            if(lockedCount == 0){
                isLocked = false;
                notify();
            }
        }
    }
}

可以看见代码的核心概念是:

首先解释lockedBy:顾名思义,临界资源被哪个线程锁住了。

加锁时,先获取当前线程。(识别谁需要锁)

Thread thread = Thread.currentThread();

判断:当临界资源已被锁上,但当前请求锁的线程又不是之前锁上临界资源的线程。那么当前请求锁的线程需要等待。

while(isLocked && lockedBy != thread){
        wait();
}

注意上面是个while,并且是个wait,因此当请求线程请求不到锁的时候,就wait了。

当时当while不满足有的3种情况:

A:当前锁没有线程使用.

B:当前锁有线程使用,当前请求锁的线程就是现在正在使用锁的线程。

C:当前锁没有线程使用,当前请求锁的线程就是现在正在使用锁的线程。(不可能出现,锁0没有被用,哪还有线程使用锁)

来看看

A:没有线程使用:

那么:

isLocked = true;
lockedCount++;
lockedBy = thread;

当前请求锁的线程先把锁加上,然后把上锁次数+1,然后把自己(本线程)赋值给lockedBy,以说明当前谁用了这把锁方便之后重入的时候做while判断。

再来看解锁:

public synchronized void unlock(){
    if(Thread.currentThread() == this.lockedBy){
        lockedCount--;
        if(lockedCount == 0){
            isLocked = false;
            notify();
        }
    }
}

首先看看要求解锁的线程是不是当前用锁的线程。不是则什么也不做。(当然不能随意让其他的线程一执行unlock代码就能解锁使用啊。那这样相当于谁都有一把钥匙了,这里这个判断也就是说明解锁的必须是加锁的)

如果要求解锁的就是加锁的线程。

那么把加锁次数减一。

然后在判断加锁次数有没有变为0。

变为0说明,这个锁已经完全解锁了。锁上标识islocked可以复位了。

并且随机唤醒某个被wait()等待的线程 :notify()

它和不可重入锁的设计不同之处:

  • 不可重入锁:只判断这个锁有没有被锁上,只要被锁上申请锁的线程都会被要求等待。实现简单

  • 可重入锁:不仅判断锁有没有被锁上,还会判断锁是谁锁上的,当就是自己锁上的时候,那么他依旧可以再次访问临界资源,并把加锁次数加一。

设计了加锁次数,以在解锁的时候,可以确保所有加锁的过程都解锁了,其他线程才能访问。不然没有加锁的参考值,也就不知道什么时候解锁?解锁多少次?才能保证本线程已经访问完临界资源了可以唤醒其他线程访问了。实现相对复杂。

总结

这个重入的概念就是,拿到锁的代码能不能多次以不同的方式访问临界资源而不出现死锁等相关问题。经典之处在于判断了需要使用锁的线程是否为加锁的线程。如果是,则拥有重(chong)入的能力。

(感谢阅读,希望对你所有帮助)

来源:https://urlify.cn/qQ7R7v945

往期精彩回顾

让人又爱又恨的 Lombok,到底该不该用

Delombok 是个啥?居然可破 Lombok?

跳槽的必要条件是有一份好的简历

时候为自己的后半生考虑了——致奔三的互联网人

https://img-blog.csdnimg.cn/img_convert/93820db7c22d46e3a9b43a3e632aba11.png" height="1425" width="1279" />

https://img-blog.csdnimg.cn/img_convert/c10ad2743e7bd65d11bb423e6340d0fb.png" />

点个赞呗


http://www.niftyadmin.cn/n/1331963.html

相关文章

推荐一款vscode的主题插件

这款主题好好看,很干净,看起来很舒服 上链接:Hipster Theme - Visual Studio MarketplaceExtension for Visual Studio Code - A very colorful theme inspired by Atoms Hipster theme.https://marketplace.visualstudio.com/items?itemNa…

那些学计算机的女生后来都怎么样了?

要不是看了上上次发的那一篇文章的评论区,我也不知道咱这里居然有这么多女生。因为咱们这里小伙伴们性别的占比常年很玄学,之前一直差不多保持在大约9比1的样子。最近还稍微好一些,勉强能占到12%了。记得我上大学那会,当时念的通信…

vscode前端开发必备插件

HTML CSS SupportHTML SnippetsJavaScript (ES6) code snippetsJavaScript and TypeScript NightlyAuto Close TagAuto Rename TagBracket Pair ColorizerGitLens — Git superchargedvueVeturVue VSCode SnippetsPath IntellisenseHipster ThemeMaterial Icon Theme

用 Nginx 禁止国外 IP 访问我的网站..

来源:toutiao.com/i6860736292339057156/先来说说为啥要写这篇文章,之前看了下 Nginx 的访问日志,发现每天有好多国外的 IP 地址来访问我的网站,并且访问的内容基本上都是恶意的。因此我决定禁止国外 IP 来访问我的网站。想要实现…

在vue项目中监听电脑网络的状态

app.vue data () {return {onLine: navigator.onLine // navigator.onLine 获取设备是否可以上网、连接网络} }, created () {// 监听网络// 网络由异常到正常时触发window.addEventListener(online, this.updateOnlineStatus)// 网络由正常到异常触发window.addEventListen…

CPU突然飙升到300%,原来是 Dubbo 惹的祸

背景:新功能开发测试完成后,准备发布上线,当发布完第三台机器时,监控显示其中一台机器CPU突然飙升到300%,Dubbo活动线程数直接飙到1000,不得不停止发布,立马回滚出问题的机器回滚之后恢复正常&a…

代码对比工具,就用这7个!

来源:搜云技术库在程序开发的过程中,程序员会经常对源代码以及库文件进行代码对比,在这篇文章里我们向大家介绍7款程序员常用的代码比较工具。一、WinMerge图片WinMerge是一款运行于Windows系统下的文件比较和合并工具,使用它可以…

大专学历造假改成了 211 拿到了抖音 Offer

如图,是脉脉最近的一个热帖,一个“大牛”因为有“技术”但是没有“学历”,拿到抖音 2-2 Offer 以后选择造假,包括学历,工作经历,那么你觉得这波骚操作如何呢?先让我们看看家的风向吧其实大家普遍…