重入锁

(1)重进入:

1.定义:重进入是指任意线程在获取到锁之后,再次获取该锁而不会被该锁所阻塞。关联一个线程持有者+计数器,重入意味着锁操作的颗粒度为“线程”。

2.需要解决两个问题

线程再次获取锁:锁需要识别获取锁的现场是否为当前占据锁的线程,如果是,则再次成功获取;

锁的最终释放:线程重复n次获取锁,随后在第n次释放该锁后,其他线程能够获取该锁。要求对锁对于获取进行次数的自增,计数器对当前锁被重复获取的次数进行统计,当锁被释放的时候,计数器自减,当计数器值为0时,表示锁成功释放。

3.重入锁实现重入性:每个锁关联一个线程持有者和计数器,当计数器为0时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;当某一线程请求成功后,JVM会记下锁的持有线程,并且将计数器置为1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为0,则释放该锁

(2)ReentrantLock是的非公平类中通过组合自定义同步器来实现锁的获取与释放。

 1 /**2 * Sync中的nonfairTryAcquire()方法实现3 * 这个跟公平类中的实现主要区别在于不会判断当前线程是否是等待时间最长的线程4 **/ 5 final boolean nonfairTryAcquire(int acquires) {6     final Thread current = Thread.currentThread();7     int c = getState();8     if (c == 0) {9         // 跟FairSync中的主要区别,不会判断hasQueuedPredecessors()
10         if (compareAndSetState(0, acquires)) {
11             setExclusiveOwnerThread(current);
12             return true;
13         }
14     }
15     else if (current == getExclusiveOwnerThread()) {
16         int nextc = c + acquires;
17         if (nextc < 0) // overflow
18             throw new Error("Maximum lock count exceeded");
19         setState(nextc);
20         return true;
21     }
22     return false;
23 }

nonfairTryAcquire()方法中,增加了再次获取同步状态的处理逻辑,通过判断当前线程是否为获取锁的线程来决定获取操作是否成功,如果是获取锁的线程再次请求,则将同步状态值进行增加并返回true,表示获取同步状态成功。

成功获取锁的现场再次获取锁,只是增加了同步状态值,要求ReentrantLock在释放同步状态时减少同步状态值。

 1 /**2 * Sync中tryRelease()3 **/4 protected final boolean tryRelease(int releases) {5     // 修改当前锁的状态6     // 如果一个线程递归获取了该锁(也就是state != 1), 那么c可能不等07     // 如果没有线程递归获取该锁,则c == 08     int c = getState() - releases;9
10 // 如果锁的占有线程不等于当前正在执行释放操作的线程,则抛出异常
11     if (Thread.currentThread() != getExclusiveOwnerThread())
12         throw new IllegalMonitorStateException();
13     boolean free = false;
14     // c == 0,表示当前线程释放锁成功,同时表示递归获取了该锁的线程已经执行完毕
15     // 则设置当前锁状态为free,同时设置锁的当前线程为null,可以让其他线程来获取
16     // 同时也说明,如果c != 0,则表示线程递归占用了锁资源,
17     // 所以锁的当前占用线程依然是当前释放锁的线程(实际没有释放)
18     if (c == 0) {
19         free = true;
20         setExclusiveOwnerThread(null);
21     }
22     // 重新设置锁的占有数
23     setState(c);
24     return free;
25 }

如果该锁被获取n次,则前(n-1)次tryRelease(int releases)方法必须返回false,而只有同步状态完全释放了,才返回true,该方法将同步状态是否为0作为最终释放的条件,当同步状态为0时,将占有线程设置为null,并返回true,表示释放成功。

对于公平锁而言

 1 /**2 * FairSync中tryAcquire()的实现3 * 返回4 *   true: 获取锁成功5 *   false: 获取锁不成功6 **/7 protected final boolean tryAcquire(int acquires) {8     // 获取当前线程9     final Thread current = Thread.currentThread();
10     // 获取锁资源的状态
11     // 0: 说明当前锁可立即获取,在此种状态下(又是公平锁)
12     // >0并且当前线程与持有锁资源的线程是同一个线程则state + 1并返回true
13     // >0并且占有锁资源的不是当前线程,则返回false表示获取不成功
14     int c = getState();
15     if (c == 0) {
16         // 在锁可以立即获取的情况下
17         // 首先判断线程是否是刚刚释放锁资源的头节点的下一个节点(线程的等待先后顺序)
18         // 如果是等待时间最长的才会马上获取到锁资源,否则不会(这也是公平与不公平的主要区别所在)
19         if (!hasQueuedPredecessors() &&
20             compareAndSetState(0, acquires)) {
21             setExclusiveOwnerThread(current);
22             return true;
23         }
24     }
25     else if (current == getExclusiveOwnerThread()) {  //线程可以递归获取锁
26         int nextc = c + acquires;
27         // 超过int上限值抛出错误
28         if (nextc < 0)
29             throw new Error("Maximum lock count exceeded");
30         setState(nextc);
31         return true;
32     }
33     return false;
34 }

与非公平唯一的区别是判断条件中多了hasQueuedPredecessors()方法,即加入了同步队列中当前节点是否有前驱节点的判断,如果该方法返回了true,则表示有线程比当前线程更早地请求获取锁,所以需要等待前驱线程获取并释放锁后才能继续获取该锁。

但是非公平锁是默认实现:非公平性锁可能使线程“饥饿”,但是极少的线程切换,可以保证其更大的吞吐量。而公平性锁,保证了锁的获取按照FIFO原则,代价是进行大量的线程切换。

(3)synchronized可重入性

同一线程在调用自己类中其他synchronized方法/块或调用父类的synchronized方法/块都不会阻碍该线程的执行,就是说同一线程对同一个对象锁是可重入的,而且同一个线程可以获取同一把锁多次,也就是可以多次重入。

Java—重入锁的理解相关推荐

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

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

  2. Java 重入锁 ReentrantLock 原理分析

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

  3. 可重入锁的理解及公平锁和非公平锁的具体实现

    可重入锁 首先结合以下两个例子理解以下可重入锁的概念. /*** 可重入锁:* 1.可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁,这样的锁就叫做可重入锁.* 2.是指在同 ...

  4. java重入锁_java并发编程:可重入锁是什么?

    释义 广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁.ReentrantLock和sync ...

  5. java重入锁,再探JAVA重入锁

    之前的文章中简单的为大家介绍了重入锁JAVA并发之多线程基础(2).这里面也是简单的为大家介绍了重入锁的几种性质,这里我们就去探索下里面是如何实现的. 我们知道在使用的时候,必须锁先有定义,然后我们再 ...

  6. java重入锁 自旋锁_java 自旋锁(可重入且无死锁)

    java自旋锁 的实现原理:如果自旋锁被另外一个线程对象持有,那么当前获取锁的线程将陷入while循环等待,直到那个持有自旋锁的线程对象释放它所持有的自旋锁,那么那些想要获取该自旋锁的线程对象 将会有 ...

  7. java 并发锁_Java并发教程–重入锁

    java 并发锁 Java的synced关键字是一个很棒的工具–它使我们可以通过一种简单可靠的方式来同步对关键部分的访问,而且也不难理解. 但是有时我们需要对同步进行更多控制. 我们要么需要分别控制访 ...

  8. Java并发教程–重入锁

    Java的synced关键字是一个很棒的工具–它使我们能够以一种简单可靠的方式来同步对关键部分的访问,而且也不难理解. 但是有时我们需要对同步进行更多控制. 我们要么需要分别控制访问类型(读取和写入) ...

  9. 聊聊高并发(二十七)解析java.util.concurrent各个组件(九) 理解ReentrantLock可重入锁

    这篇讲讲ReentrantLock可重入锁,JUC里提供的可重入锁是基于AQS实现的阻塞式可重入锁.这篇 聊聊高并发(十六)实现一个简单的可重入锁 模拟了可重入锁的实现.可重入锁的特点是: 1. 是互 ...

最新文章

  1. Membership学习(二)membership入门
  2. css3:绘制android3蜂巢Honeycomb
  3. java 字符串驻留_java String 以及字符串直接量 与 字符串驻留池 ...
  4. [原创] 盟军敢死队2 - 3D模型/动作浏览器
  5. sql server 2008安装_性能不够?基于时序数据库的Zabbix 5.2安装指南
  6. The used SELECT statements have a different number of columns 错误解决
  7. HDU 5996 dingyeye loves stone [阶梯Nim]
  8. Intelli IDEA+jdk++maven+tomcat环境配置
  9. matlab+yalmip+mosek/cplex安装配置
  10. ModuleNotFoundError: No module named ‘views‘
  11. 使用cephadm搭建ceph(octopus)过程
  12. pyecharts学习笔记
  13. python实现CAPM模型
  14. EXCEL如何将一列转为一行
  15. 传音控股再度携手联合国难民署 驰援非洲儿童教育事业
  16. UE学习笔记01(3月)
  17. 【vim小小记】vim的复制粘贴(包括系统剪贴板)
  18. Day25:Python基础编程(函数)能力训练50天——回文数
  19. 猿创征文|我的四个月Java学习成长之路——从基础到框架再到项目
  20. 天空之城 10孔口琴

热门文章

  1. [振动力学] 使用能量法求质量矩阵的时候需要注意刚体运动分解
  2. 排序算法——十大排序算法的图示与实现
  3. ubuntu18.04如何安装mysql
  4. Mybatis(13)动态sql语句if/where/foreach
  5. 计算机网络(2)-数据链路层流量控制
  6. 卷积神经网络系列之softmax,softmax loss和cross entropy
  7. vant表单组件+iconfont组合使用 - 代码篇
  8. (自定义组件)通用- X轴横向:溢出滚动 (含代码)- 案例篇
  9. 小说精品屋plus v2.7.0源码
  10. WordPress技术资讯博客模板