可重入锁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原理分析相关推荐

  1. Java 重入锁 ReentrantLock 原理分析

    1.简介 可重入锁ReentrantLock自 JDK 1.5 被引入,功能上与synchronized关键字类似.所谓的可重入是指,线程可对同一把锁进行重复加锁,而不会被阻塞住,这样可避免死锁的产生 ...

  2. Java 线程同步组件 CountDownLatch 与 CyclicBarrier 原理分析

    1.简介 在分析完AbstractQueuedSynchronizer(以下简称 AQS)和ReentrantLock的原理后,本文将分析 java.util.concurrent 包下的两个线程同步 ...

  3. 某电批锁付一颗螺丝的原理分析

    目录 1.锁付曲线图 2.锁付原理分析 内容 1.锁付曲线图 2.锁付原理分析 2.1 电批软启动(即速度慢慢提高): 2.2 螺丝前进遇到阻力,电批产生扭矩: 2.3 控制器侦测到电批产生扭矩后,会 ...

  4. 【重难点】【JUC 04】synchronized 原理、ReentrantLock 原理、synchronized 和 Lock 的对比、CAS 无锁原理

    [重难点][JUC 04]synchronized 原理.ReentrantLock 原理.synchronized 和 Lock 的对比.CAS 无锁原理 文章目录 [重难点][JUC 04]syn ...

  5. java并发包线程池原理分析锁的深度化

    java并发包&线程池原理分析&锁的深度化 并发包 同步容器类 Vector与ArrayList区别 1.ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素 ...

  6. MySQL事务原理分析(ACID特性、隔离级别、锁、MVCC、并发读异常、并发死锁以及如何避免死锁)

    MySQL事务原理分析(ACID特性.隔离级别.锁.MVCC.并发读异常.并发死锁以及如何避免死锁) 一.事务 目的 组成 特征 事务空间语句 二.ACID特性 原子性(A) 隔离性(I) 持久性(d ...

  7. 【线程、锁】Condition使用以及Condition原理分析

    文章目录 1. Condition作用 1.1 什么是线程通信? 1.2 Condition接口常用方法 2. Condition实战例子 3. 原理分析 3.1 Condition 3.2 awai ...

  8. java中的账户冻结原理_java可重入锁(ReentrantLock)的实现原理

    前言 相信学过java的人都知道 synchronized 这个关键词,也知道它用于控制多线程对并发资源的安全访问,兴许,你还用过Lock相关的功能,但你可能从来没有想过java中的锁底层的机制是怎么 ...

  9. 原理剖析(第 012 篇)Netty之无锁队列MpscUnboundedArrayQueue原理分析

    原理剖析(第 012 篇)Netty之无锁队列MpscUnboundedArrayQueue原理分析 - 一.大致介绍 1.了解过netty原理的童鞋,其实应该知道工作线程组的每个子线程都维护了一个任 ...

最新文章

  1. python软件是免费的吗-python属于软件吗
  2. 心得体悟帖---14、没有自己精品项目永远是个弟弟
  3. SQL server与Oracle触发器的创建与使用
  4. CTFshow 文件上传 web154
  5. jsp mysql 分页插件_知识分享:Mybatis框架如何使用分页插件呢?
  6. boost log 能不能循环覆盖_记一次for循环中let是声明还是赋值
  7. 关于perl中DBD for Oracle的安装
  8. wordpress index.php 跳转,wordpress点击内容页跳转到其他url的解决方法
  9. idea关闭coverage
  10. 65 年来,全英国向他道歉三次,图灵,计算机人不能忘记的男人
  11. c++ primer 6.3.3节练习答案
  12. JavaScript —— Symbol数据类型的拓展
  13. eslint 快捷键设置_eslint的妙用和快捷修复
  14. 天正电气图例_天正电气CAD教程之符号篇 - CAD自学网
  15. VMware Workstation虚拟机环境下Xubuntu系统如何设置中文
  16. vscode 格式化后函数后空格被删
  17. 唉~看看google搜索的两个关键字的结果吧
  18. html flappybird小游戏代码,原生js实现Flappy Bird小游戏
  19. listview winfrom 表头_c# listview添加表头
  20. Stacked Attention Networks for Image Question Answering(用于图像问答的堆叠注意力网络)

热门文章

  1. [蓝桥杯][2019年第十届真题c/c++B组]完全二叉树的权值
  2. get请求中传json参数报400的错误_诡异 | Spark使用get_json_object函数
  3. 编译型和解释型语言的区别
  4. 如何查看文件的字符集
  5. java.lang.ClassNotFoundException: org.apache.jsp.WEB_002dINF.classes.views.index_jsp
  6. awk实战:文件里面全是数字,实现大于100的求和并打印出所在行和这些数字的总和...
  7. jQuery导航菜单防刷新
  8. Linux概述及centos版本介绍和下载地址
  9. 查询一个ID出现2种结果的情况
  10. RHEL5***检测系统(IDS)snort的安装与配置,建议用BASE做控制台