ReentrantLock 是一种可重入的互斥锁,它不像 synchronized关键字一样支持隐式的重进入,但能够使一个线程(不同的方法)重复对资源的重复加锁而不受阻塞。

ReentrantLock 的 Java类图:

其中抽象静态内部类 Sync 继承了 AQS,可见 ReentrantLock 是通过组合自定义同步器来实现锁的获取与释放。

ReentrantLock 的构造函数能控制锁的公平性表现:

1     public ReentrantLock(boolean fair) {
2 sync = fair ? new FairSync() : new NonfairSync();
3 }

公平锁的够减少“饥饿”发生概率,等待越久的请求越能够优先的到满足。

公平性与否是针对获取锁而言的,一个锁若是公平的,那么锁的获取顺序就应该符合请求的绝对时间顺序,先到先得。

公平性锁每次都是从同步队列中的第一个节点获取到锁,而非公平性锁会出现一个线程连续获取锁的情况,特别是刚释放锁的线程在次获取同步状态的几率会更大,使得其他线程在同步队列中等待。

在系统线程上下文切换方面上,非公平性锁的切换次数会明显少于公平性锁,因为公平性锁的切换开销相对更大,但是极少的线程切换能保证更大吞吐量。

ReentrantLock 类代码的基本结构:

 1 public class ReentrantLock implements Lock, java.io.Serializable {
2 private final Sync sync;
3
4 //默认无参构造函数,默认为非公平锁
5 public ReentrantLock() {
6 sync = new NonfairSync();
7 }
8
9 //带参数的构造函数,决定是公平锁还是非公平锁
10 public ReentrantLock(boolean fair) {
11 sync = fair ? new FairSync() : new NonfairSync();
12 }
13
14 //抽象基类继承AQS,公平锁与非公平锁继承该类,并分别实现其lock()方法
15 abstract static class Sync extends AbstractQueuedSynchronizer {
16 abstract void lock();
17 //省略..
18 }
19
20 //非公平锁实现
21 static final class NonfairSync extends Sync {...}
22
23 //公平锁实现
24 static final class FairSync extends Sync {....}
25
26 //锁实现,根据具体子类实现调用
27 public void lock() {
28 sync.lock();
29 }
30
31 //响应中断的获取锁
32 public void lockInterruptibly() throws InterruptedException {
33 sync.acquireInterruptibly(1);
34 }
35
36 //尝试获取锁,默认采用非公平锁方法实现
37 public boolean tryLock() {
38 return sync.nonfairTryAcquire(1);
39 }
40
41 //超时获取锁
42 public boolean tryLock(long timeout, TimeUnit unit)
43 throws InterruptedException {
44 return sync.tryAcquireNanos(1, unit.toNanos(timeout));
45 }
46
47 //释放锁
48 public void unlock() {
49 sync.release(1);
50 }
51
52 //创建锁条件(从Condetion来理解,就是创建等待队列)
53 public Condition newCondition() {
54 return sync.newCondition();
55 }
56
57 //省略....
58 }

ReentrantLock 释放锁的方法,在抽象静态内部类 Sync 中,它会检查当前线程同步状态值(重复获取一次锁,状态值会增加),在释放同步状态时减少同步状态值,若该锁获取了 n 次,那么前(n-1)次返回的都是 false,只有同步状态完全释放了(c为0),才会把占有该资源的线程设置为空,并返回 true。

 1     protected final boolean tryRelease(int releases) {
2 int c = getState() - releases;
3 if (Thread.currentThread() != getExclusiveOwnerThread())
4 throw new IllegalMonitorStateException();
5 boolean free = false;
6 if (c == 0) {
7 free = true;
8 setExclusiveOwnerThread(null);
9 }
10 setState(c);
11 return free;
12 }

Java并发:重入锁 ReentrantLock(一)的更多相关文章

  1. 轻松学习java可重入锁(ReentrantLock)的实现原理

    转载自https://blog.csdn.net/yanyan19880509/article/details/52345422,(做了一些补充) 前言 相信学过java的人都知道 synchroni ...

  2. 轻松学习java可重入锁(ReentrantLock)的实现原理(转 图解)

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

  3. java 可重入锁ReentrantLock的介绍

    一个小例子帮助理解(我们常用的synchronized也是可重入锁) 话说从前有一个村子,在这个村子中有一口水井,家家户户都需要到这口井里打水喝.由于井水有限,大家只能依次打水.为了实现家家有水喝,户 ...

  4. java可重入锁reentrantlock

    public class ReentrantDemo { //重入锁 保护临界区资源count,确保多线程对count操作的安全性 /*public static ReentrantLock rtlo ...

  5. Java 重入锁 ReentrantLock 原理分析

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

  6. Java 显示锁 之 重入锁 ReentrantLock(七)

    ReentrantLock 重入锁简介 重入锁 ReentrantLock,顾名思义,就是支持同一个线程对资源的重复加锁.另外,该锁还支持获取锁时的公平与非公平性的选择. 重入锁 ReentrantL ...

  7. synchronized关键字,Lock接口以及可重入锁ReentrantLock

    多线程环境下,必须考虑线程同步的问题,这是因为多个线程同时访问变量或者资源时会有线程争用,比如A线程读取了一个变量,B线程也读取了这个变量,然后他们同时对这个变量做了修改,写回到内存中,由于是同时做修 ...

  8. 17_重入锁ReentrantLock

    [概述] 重入锁可以完全代替synchronized关键字. 与synchronized相比,重入锁ReentrantLock有着显示的操作过程,即开发人员必须手动指定何时加锁,何时释放锁,所以重入锁 ...

  9. Java不可重入锁和可重入锁的简单理解

    基础知识 Java多线程的wait()方法和notify()方法 这两个方法是成对出现和使用的,要执行这两个方法,有一个前提就是,当前线程必须获其对象的monitor(俗称“锁”),否则会抛出Ille ...

  10. Java并发(九):重入锁 ReentrantLock

    先做总结: 1.为什么要用ReentrantLock? (1)ReentrantLock与synchronized具有相同的功能和内存语义: (2)synchronized是重量级锁,性能不好.Ree ...

随机推荐

  1. RMI源码调试

    看RMI漏洞时候,对其漏洞原理并不是很理解,所以简单调试了下源码加强下漏洞理解 由于要调试到RegistryImpl_Stub这种动态类,刚开始用的源码版本是JDK8u141,后来发现源码有些地方进行 ...

  2. vue中如何深度监听一个对象?

    大家都知道,Vue项目中对数据的监听,提供了一个很好的钩子watch,watch可以极其方便的监听我们常用数据类型值的变化,但通常当我们想监听一个对象中,某个属性值的变化时,很难达到我们预期的效果.那 ...

  3. ClickOnce 获取客户端发布版本号

    https://social.microsoft.com/Forums/es-ES/26786b8d-0155-4261-9672-11b786d8c1d6/clickonceandsetup /// ...

  4. leetcode-螺旋矩阵(指针)

    给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素. 示例 1: 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 输出:[1,2 ...

  5. 【noip1998】题解:2的幂次方

    思路:设递归函数dfs(x)用于输出x的幂次方 最容易的思路:0不输出,1输出为2(0),2输出2,剩下的递归执行. 每一次递归:例如7,拆分为4+3,先拆出最大的是2的次方的数出来,输出4,再把3分 ...

  6. C++吃金币小游戏

    上图: 游戏规则:按A,D键向左和向右移动小棍子,$表示金币,0表示炸弹,吃到金币+10分,吃到炸弹就GAME OVER. 大体思路和打字游戏相同,都是使用数组,refresh和run函数进行,做了一 ...

  7. 数据结构逆向分析-Vector

    数据结构逆向分析-Vector 这个应该是家喻户晓了的东西把,如果说C/C++程序员Vector都不用的话,可能就是一个不太好的程序员. Vector就是一个STL封装的动态数组,数组大家都知道是通过 ...

  8. jvm运行过程

    ------------恢复内容开始------------ 把文件编译成字节码文件的叫编译器的前端, 线程共享的方法去和堆,非线程共享的:java虚拟机栈,本地方法栈,还有程序计数器 都是每个线程独 ...

  9. nuxt.js同路由跳转参数不同,mounted不执行时

    watch: { '$route'(to, from) { if (to.fullPath !== from.fullPath) { this.$nextTick(() => { // 不加th ...

  10. Java基础系列(36)- 数组三种初始化及内存分析

    内存分析 数组三种初始化 静态初始化 int[] a = {1,2,3}; Man[] mans = {new Man(1,1),new Man(2,2)} 动态初始化 int[] a = new i ...