可重复锁ReentrantLock原理分析
可重入锁ReentrantLock实现层面依赖
一、CAS(compareAndSet)
LockSupport
基本的方法
park
park使得当前线程放弃cpu 进入等待(waiting)状态 操作系统不会再对其进行调度直到其他线程对它调用了unpark方法,其中unpark方法使得参数指定的线程恢复可运行状态
[1] part和Thread.yield()区别
yield 只是告诉操作系统可以让其他线程先运行,但是自己可以仍是运行态
park 方法则是放弃线程的运行资格,使得线程进入 WAITING 等待状态
[2] 响应中断
park 方法是响应中断的,当有中断发生时,park方法会返回,并且重新设置线程的中断状态
[3]2个变体
parkNanos: 可以指定等待的最长时间,参数是相对于当前时间的纳秒数
parkUntil:可以指定最长等待的时间,参数是绝对时间,相对于纪元时的毫秒数
当等待超时,方法就会返回。同时还有一些其他的变体,可以指定一个对象,表示是由于该对象而进行等待,以便于调试,一般情况下传递的参数为 this
getBlocker
二、AQS
提供了一个state字段 被volatile修饰 保证内存可见性、顺序性
AQS内部维护了一个等待队列,借助CAS方法实现无阻塞算法进行更新
三、ReentrantLock
Sync是抽象类
NonfairSync是 fair 为 false 时使用的类[默认]
FairSync 是 fair 为 true 时需要使用的类
lock实现
该方法被子类重写
如果没有被锁定,则使用CAS进行锁定;如果当前线程已经被锁定,则增加锁定次数。如果 tryArquire方法返回false,则acquire方法会继续调用acquireQueued(addWaiter(Node.EXCLUSIVE), arg)。其中,addWaiter 会新建一个节点 Node,代表当前线程,然后加入内部的等待队列中。在当如等待队列之后,调用 acquireQueued 来尝试获取锁,其代码为
是一个死循环,在每次循环中,首先检查当前节点是否为第一个等待的节点,
如果是且能获取到锁,就将当前节点从等待队列中移除并且返回,
否则通过parkAndCheckInterrupt方法最终调用 LockSupport.park而放弃CPU,
进入等待状态,在被唤醒之后检查是否发生了中断,记录中断标志。并且返回中断标志
如果能获得锁则立即获得,如若不能则加入等待队列。被唤醒之后检查自己是否为第一个等待的线程,如果是且能获得锁则返回,否则继续等待。如果在该过程中发生了中断, lock 会记录中断标志位,但是不会提前返回或者抛除异常
unlock实现
tryRelease 方法会修改线程状态并且释放锁, unparkSuccessor 方法会调用 LockSupport.unpark 将第一个等待的线程唤醒
公平锁和非公平锁
公平锁比非公平锁在源码实现上就多了一个检查:当没有其他等待时间更长的线程时,才能获取到锁
公平锁模型
初始化时, state=0,表示没有线程过来抢锁。这时候,A线程请求锁,占了锁,把state+1
线程A取得了锁,把 state原子性+1,这时候state被改为1,A线程继续执行其他任务,然后线程B请求锁,线程B无法获取锁,生成节点进行排队
初始化的时候,会生成一个空的头节点,然后才是B线程节点,这时候,如果线程A又请求锁,是否需要排队?答案当然是否定的,否则就直接死锁了。当A再次请求锁
可重入锁:就是一个线程在获取了锁之后,再次去获取了同一个锁,这时候仅仅是把状态值进行累加。如果线程A释放了一次锁
仅仅是把状态值减了,只有线程A把此锁全部释放了,状态值减到0了,其他线程才有机会获取锁。当A把锁完全释放后,state恢复为0,然后会通知队列唤醒B线程节点,使B可以再次竞争锁。当然,如果B线程后面还有C线程,C线程继续休眠,除非B执行完了,通知了C线程。注意,当一个线程节点被唤醒然后取得了锁,对应节点会从队列中删除
非公平锁模型
当线程A执行完之后,要唤醒线程B是需要时间的,而且线程B醒来后还要再次竞争锁,所以如果在切换过程当中,来了一个线程C,那么线程C是有可能获取到锁的,如果C获取到了锁,B就只能继续休眠了
为什么不默认是公平锁
保证公平整体性能会比较低,其原因不是因为检查慢,而是因为会让活跃线程无法得到锁,从而进入等待状态,引起了频繁的上下文切换,降低了整体的效率
ReentrantLock tryLock()方法使用的是非公平锁
和synchronized比较
ReentrantLock可以实现与 synchronized 相同的语义 而且支持以非阻塞方式获取锁,也可以想用中断,限时阻塞,更为灵活;synchronized 的使用更为简单,代码量也更少
synchronized 代表的是一种声明式编程思维 由 Java 系统负责实现 程序员并不清楚实现细节;显式锁代表一种命令式编程思维,使用者需要实现所有的细节
声明式编程的好处除了简单,在性能上也有所体现。 在较新版本的 JVM 上,ReentrantLock和synchronized的性能是接近的, 并且 Java 编译器和虚拟机会不断优化 synchronized 的实现,比如自动分析 synchronized 的使用,对于没有锁竞争的场景,自动忽略对获取锁/释放锁的调用
能用 synchronized 就用 synchronized,不满足使用要求的时候考虑使用 ReentrantLock
代码资源
https://gitee.com/pingfanrenbiji/myconcurrent/blob/master/src/main/java/pers/hanchao/concurrent/reentrantLock/LockSupportTest.java
参考文章
https://blog.csdn.net/u011669700/article/details/80070892
https://blog.csdn.net/yanyan19880509/article/details/52345422
可重复锁ReentrantLock原理分析相关推荐
- Java 重入锁 ReentrantLock 原理分析
1.简介 可重入锁ReentrantLock自 JDK 1.5 被引入,功能上与synchronized关键字类似.所谓的可重入是指,线程可对同一把锁进行重复加锁,而不会被阻塞住,这样可避免死锁的产生 ...
- Java 线程同步组件 CountDownLatch 与 CyclicBarrier 原理分析
1.简介 在分析完AbstractQueuedSynchronizer(以下简称 AQS)和ReentrantLock的原理后,本文将分析 java.util.concurrent 包下的两个线程同步 ...
- 某电批锁付一颗螺丝的原理分析
目录 1.锁付曲线图 2.锁付原理分析 内容 1.锁付曲线图 2.锁付原理分析 2.1 电批软启动(即速度慢慢提高): 2.2 螺丝前进遇到阻力,电批产生扭矩: 2.3 控制器侦测到电批产生扭矩后,会 ...
- 【重难点】【JUC 04】synchronized 原理、ReentrantLock 原理、synchronized 和 Lock 的对比、CAS 无锁原理
[重难点][JUC 04]synchronized 原理.ReentrantLock 原理.synchronized 和 Lock 的对比.CAS 无锁原理 文章目录 [重难点][JUC 04]syn ...
- java并发包线程池原理分析锁的深度化
java并发包&线程池原理分析&锁的深度化 并发包 同步容器类 Vector与ArrayList区别 1.ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素 ...
- MySQL事务原理分析(ACID特性、隔离级别、锁、MVCC、并发读异常、并发死锁以及如何避免死锁)
MySQL事务原理分析(ACID特性.隔离级别.锁.MVCC.并发读异常.并发死锁以及如何避免死锁) 一.事务 目的 组成 特征 事务空间语句 二.ACID特性 原子性(A) 隔离性(I) 持久性(d ...
- 【线程、锁】Condition使用以及Condition原理分析
文章目录 1. Condition作用 1.1 什么是线程通信? 1.2 Condition接口常用方法 2. Condition实战例子 3. 原理分析 3.1 Condition 3.2 awai ...
- java中的账户冻结原理_java可重入锁(ReentrantLock)的实现原理
前言 相信学过java的人都知道 synchronized 这个关键词,也知道它用于控制多线程对并发资源的安全访问,兴许,你还用过Lock相关的功能,但你可能从来没有想过java中的锁底层的机制是怎么 ...
- 原理剖析(第 012 篇)Netty之无锁队列MpscUnboundedArrayQueue原理分析
原理剖析(第 012 篇)Netty之无锁队列MpscUnboundedArrayQueue原理分析 - 一.大致介绍 1.了解过netty原理的童鞋,其实应该知道工作线程组的每个子线程都维护了一个任 ...
最新文章
- python软件是免费的吗-python属于软件吗
- 心得体悟帖---14、没有自己精品项目永远是个弟弟
- SQL server与Oracle触发器的创建与使用
- CTFshow 文件上传 web154
- jsp mysql 分页插件_知识分享:Mybatis框架如何使用分页插件呢?
- boost log 能不能循环覆盖_记一次for循环中let是声明还是赋值
- 关于perl中DBD for Oracle的安装
- wordpress index.php 跳转,wordpress点击内容页跳转到其他url的解决方法
- idea关闭coverage
- 65 年来,全英国向他道歉三次,图灵,计算机人不能忘记的男人
- c++ primer 6.3.3节练习答案
- JavaScript —— Symbol数据类型的拓展
- eslint 快捷键设置_eslint的妙用和快捷修复
- 天正电气图例_天正电气CAD教程之符号篇 - CAD自学网
- VMware Workstation虚拟机环境下Xubuntu系统如何设置中文
- vscode 格式化后函数后空格被删
- 唉~看看google搜索的两个关键字的结果吧
- html flappybird小游戏代码,原生js实现Flappy Bird小游戏
- listview winfrom 表头_c# listview添加表头
- Stacked Attention Networks for Image Question Answering(用于图像问答的堆叠注意力网络)
热门文章
- [蓝桥杯][2019年第十届真题c/c++B组]完全二叉树的权值
- get请求中传json参数报400的错误_诡异 | Spark使用get_json_object函数
- 编译型和解释型语言的区别
- 如何查看文件的字符集
- java.lang.ClassNotFoundException: org.apache.jsp.WEB_002dINF.classes.views.index_jsp
- awk实战:文件里面全是数字,实现大于100的求和并打印出所在行和这些数字的总和...
- jQuery导航菜单防刷新
- Linux概述及centos版本介绍和下载地址
- 查询一个ID出现2种结果的情况
- RHEL5***检测系统(IDS)snort的安装与配置,建议用BASE做控制台