对可重入锁和不可重入锁的理解

可重入锁:ReentrantLock
在学JUC的时候,听到可重入锁这个词,不理解它的概念,网上搜索一番,还是有点迷糊,所以自己再来做一下笔记,理一理思路。

一、锁是什么?

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

二、可重入锁与不可重入锁的区别?

1、不可重入锁:

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

2、可重入锁:

不仅判断锁有没有被锁上,还会判断锁是哪个线程锁上的,当就是当前锁上的时候,那么他依旧可以再次访问临界资源,并把加锁次数加一。

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

3、结论:

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

三、下面使用代码来说明

1、不可重入锁的理解:

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的锁未解锁前,其他代码块无法使用此锁来加锁。这是由这个不可重入锁决定的。

2、不可重入锁的加锁与解锁(实现):

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:争抢同一临界资源的实质就是对同一把锁的争抢)

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

3、可重入锁的实现:

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();}}}
}

现在我们来理解这段代码,先看加锁

3.1、lock()

 isLocked:锁的状态。lockedBy:临界资源被哪个线程锁住了。Thread thread = Thread.currentThread();    加锁时,先获取当前线程,识别谁需要锁**while 判断:当临界资源已被锁上,但当前请求锁的线程又不是之前锁上临界资源的线程。那么当前请求锁的线程需要等待。**
while(isLocked && lockedBy != thread){wait();
}

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

不满足while判断条件的有3种情况:

  1. 当前锁没有线程使用,即 isLocked == false。
  2. 当前锁有线程使用 isLocked == true,当前请求锁的线程就是现在正在使用锁的线程 lockedBy == thread。
  3. 当前锁没有线程使用,当前请求锁的线程就是现在正在使用锁的线程。(不可能出现,“当前锁莫瑶线程使用 isLocked == false” 与 "请求锁的线程就是现在正在用锁的线程 isLocked == true"两者之间是矛盾的)

在while条件不满足时,那么当前线程可以加锁:

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

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

3.2、unlock()

再来看解锁:

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

首先看看要求解锁的线程是不是当前正在使用锁的线程。不是则什么也不做。(这个判断使为了保证当前要解锁的线程必须也是加锁的线程,谁加的谁来解。否则其他线程也能随意的执行unlock代码就能解锁,那这样相当于谁都有一把钥匙了,加锁也失去了意义)

如果解锁的就是加锁的线程。
那么把加锁次数减一。
然后在判断加锁次数有没有变为0。
变为 0 说明,这个锁已经完全解锁了。
锁状态标志 islocked 就可以复位为 false了。
并且随机唤醒某个被 wait() 等待的线程 :notify()

这就是重入锁的设计。

再次回顾上文所述的

4、可重入锁和不可重入锁的区别:

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

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

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

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

怎么样,现在是不是理解更清晰了?

参考原文:https://blog.csdn.net/qq_29519041/article/details/86583945

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/548769.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows Phone 7开发一月谈(3)

如何获知手机与PC相连Spb Shell 技术研究windows mobile 6.0 C# 如何获得 SIM卡 ICCID ?mobile上如何掉用API来挂掉电话关于全屏程序下输入法的显示问个获取主机IP地址的问题?在设置-电话界面中铃声播放问题怎样获取TAPI的LINECALLSTATE_RINGBACK消息Dir…

Synchronized 和 Lock 区别

Synchronized 和 Lock 区别 Synchronized 是内置的Java关键字, Lock 是一个Java类Synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁Synchronized 会自动释放锁,lock 必须要手动释放锁!如果不释放锁,会…

对HashMap数据结构的理解——加载因子和初始容量

先看源码&#xff1a; 解释一下位移运算&#xff1a; 1<<4 是位移运算的表示&#xff0c;为十进制16 1的二进制表示&#xff1a;1 左移4位之后的二进制表示为B&#xff08;10000&#xff09; D&#xff08;16&#xff09; 更简单的计算方法就是 1<< n 等效于 1 乘…

objective-c 使用NSNumber 将int float long等数据类型加入到数组或字典中

objective-c 使用NSNumber 将int float long等数据类型加入到数组或字典中设置值和取值如下代码&#xff1a;NSNumber *number[NSNumber numberWithInt:45]; NSLog("NSNumber %d",[number intValue]);

远程服务器电脑的设置

1、因为我要远程的电脑已经被人家设置过了远程了&#xff0c;而他已经将远程的端口改为4816&#xff0c;所以我一直以为是3389端口&#xff0c;上网搜索了很久都没有发现什么问题出现在哪&#xff1f;命令环境下查看端口状态都还是关着的&#xff0c;没有打开&#xff0c;远程一…

巧用加密方法保障电子邮件系统安全

近几年来&#xff0c;针对公司的间谍活动越来越严重。因此部署某种加密系统以确保窥探者不能从其截获的消息中破译什么内容&#xff0c;或者不能因为电脑被窃取而丢失信息是非常有意义的。不管是客户的数据&#xff0c;雇员数据&#xff0c;知识产权还是财务信息&#xff0c;丢…

“习惯性思维”引起的血案

好久没有更新了&#xff0c;一客户因为IT规划问题&#xff0c;需要将Citrix服务器迁到新的域&#xff0c;Citrix服 务器需要重新配置。但是当我重新配置完站点后&#xff0c;发现无论如何都登录不了。 错误截图&#xff1a; 我按照传统的思路来解决问题&#xff0c; 1、查看服务…

折腾中兴V880

一、验屏&#xff1a;输入*983*0#&#xff0c;选择LCD&#xff0c;按返回键换色&#xff0c;即可检验。二、Root。1、先设置手机为USB调试模式&#xff0c;设置方法&#xff1a;menu——设置——应用程序——开发&#xff0c;打开“USB”调试和“保持唤醒状态”下载豌豆荚&…

剑指 Offer 32 . 从上到下打印二叉树

main函数测试代码&#xff1a; 按标准输入输出&#xff0c;比如输入&#xff1a; 3,9,20,null,null,15,7 public static void main(String[] args) {//输入3,9,20,null,null,15,7Scanner sc new Scanner(System.in);String s sc.nextLine();String[] split s.split(",…

HTTP 头部解释

HTTP&#xff08;HyperTextTransferProtocol&#xff09;是超文本传输协议的缩写&#xff0c;它用于传送WWW方式的数据&#xff0c;关于HTTP协议的详细内容请参考RFC2616。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求&#xff0c;请求头包含请求的方法、URI、协议…

剑指 Offer 52. 两个链表的第一个公共节点

剑指 Offer 52. 两个链表的第一个公共节点 输入两个链表&#xff0c;找出它们的第一个公共节点。 思想&#xff1a;双指针法&#xff0c;浪漫相遇 public static ListNode getIntersectionNode(ListNode headA, ListNode headB) {ListNode pointA headA;ListNode pointB he…

Android 创世纪 第二天

第二天&#xff0c;google说&#xff0c;荒芜要被开垦&#xff0c;系统便运作了&#xff0c;它是linux。 --xxx 荒蛮大地就要变得肥沃&#xff0c;linux已经运行起来了。。。。 linux就不多讲了&#xff0c;这里只讲讲被google大刀阔斧改了内核后的linux。 第一天最后&#xff…

“.NET研究”谈谈C# 4.0新特性“缺省参数”的实现

C#4.0关于缺省参数的新特性&#xff0c;相信大家都不会陌生。所谓缺省参数&#xff0c;顾名思义&#xff0c;就是在声明方法的某个参数的时候为之指定一个默认值&#xff0c;在调用该方法的时候如果采用该默认值&#xff0c;你就无须指定该参数。和很多语言层面特性&#xff08…

IDEA查看源码时总是出现.class而不是.java源码(解决办法)

自己安装的JDK8里面就有源码&#xff0c;就是图中的src.zip&#xff0c;我还傻乎乎的跑去下。 我参考下面这个链接解决了这个问题&#xff1a; https://www.it610.com/article/1283023085871579136.htm 特别注意其中的一句话&#xff1a;把SDKs中多余的jdk删掉留一个就好&am…

ASP“.NET研究”.NET中的认证与授权

用户认证 .net提供了3种用户认证的方式&#xff0c;分别是Windows,Forms&#xff0c;Passport。这几种形式的定义可以在网站根目录下Web.config中的authentication节点中看见。Windows是默认的验证形式&#xff0c;它是根据机器的访问权限来判断的。Passport是微软提供的一种验…

针对资源管理器文件夹右键一直转圈圈卡死的问题

问题描述 每次打开资源管理器&#xff0c;文件夹右键就会一直转圈圈&#xff0c;转到资源管理器自动退出 解决方法 网上试了很多种方法&#xff0c;都没有解决我的问题&#xff0c;偶然在运行菜单里看到两个根本不是我装的疑似携带病毒类的软件&#xff0c;把他们都卸载之后…

用NuGet掌管你的Vi“.NET研究”sual Studio扩展

如果你使用Visual Studio 2010&#xff0c;那么 NuGet 可以使你的生活更加美好。当你项目里要引用到的一些库时候&#xff0c;比如JQuery 库或者 NHibernate, NUnit, log4net 你就可以考虑使用NuGet。它可以辅助你安装或者更新这些库。 当然我不得不继续说下去从安装到使用&…

cmd窗口使用python提示“Python not found”,可能是环境变量配置的原因

问题1 打开命令行窗口使用python命令无法直接进入python环境&#xff0c;但是从python的安装目录下就可以进去 问题原因 没有配置系统环境变量&#xff0c;需要把python安装路径添加到path环境变量中 环境变量配置&#xff0c;可以参考菜鸟教程 问题2 配置了环境变量之后…

vim 高亮显示php代码

vim是一款跨平台编辑器&#xff0c;可以在linux下使用&#xff0c;也可以在windows下使用高亮显示php代码 进入vim后&#xff0c;在普通模式下输入如下命令&#xff0c;开启php代码高亮显示 WwwChinazcom :syntax enable :source $VIMRUNTIME/syntax/php.vim转载于:https://w…

无法打开caffe.pb.h, no such file or directory错误

问题&#xff1a; 使用VS2013生成caffe解决方案的过程中&#xff0c;出现 无法打开caffe.pb.h&#xff0c;no such file or directory ,解决方案 &#xff1a; 参考博客&#xff1a;[caffe] 无法打开caffe.pb.h, no such file or directory错误 博客地址&#xff1a;https://b…