ReentrantLock是lock接口的一个实现类,里面实现了可重入锁和公平锁非公平锁

ReentrantLock公平锁和不公平锁实现原理

公平锁会获取锁时会判断阻塞队列里是否有线程再等待,若有获取锁就会失败,并且会加入阻塞队列

非公平锁获取锁时不会判断阻塞队列是否有线程再等待,所以对于已经在等待的线程来说是不公平的,但如果是因为其它原因没有竞争到锁,它也会加入阻塞队列

进入阻塞队列的线程,竞争锁时都是公平的,应为队列为先进先出(FIFO)

默认实现的是非公平锁

public ReentrantLock() {
//非公平锁
sync = new NonfairSync();
}

还提供了另外一种方式,可传入一个boolean值,true时为公平锁,false时为非公平锁

//公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}

非公平锁

非公平锁获取锁nonfairTryAcquire方法,对锁状态进行了判断,并没有把锁加入同步队列中

    static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L; final void lock() {
//比较当前状态 如果持有者是当前线程
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
//如果不是 尝试获取锁
acquire(1);
} protected final boolean tryAcquire(int acquires) {
//获取锁
return nonfairTryAcquire(acquires);
}
} final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//判断当前对象是否被持有
if (c == 0) {
//没有持有就直接改变状态持有锁
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//若被持有 判断锁是否是当前线程 也是可重入锁的关键代码
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}

公平锁

代码和nonfairTryAcquire唯一的不同在于增加了hasQueuedPredecessors方法的判断

static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L; protected final boolean tryAcquire(int acquires) {
//获取当前线程
final Thread current = Thread.currentThread();
int c = getState();
//判断当前对象是否被持有
if (c == 0) {
//如果等待队列为空 并且使用CAS获取锁成功 否则返回false然后从队列中获取节点
if (!hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {
//把当前线程持有
setExclusiveOwnerThread(current);
return true;
}
}
//若被持有 判断锁是否是当前线程 可重入锁的关键代码
else if (current == getExclusiveOwnerThread()) {
//计数加1 返回
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
//不是当前线程持有 执行
return false;
}
}

acquire()获取锁

    public final void acquire(int arg) {
//如果当前线程尝试获取锁失败并且 加入把当前线程加入了等待队列
if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//先中断当前线程
selfInterrupt();
}

关键代码

就是tryAcquire方法中hasQueuedPredecessors判断队列是否有其他节点

public final boolean hasQueuedPredecessors() {
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}

可重入性实现原理

在线程获取锁的时候,如果已经获取锁的线程是当前线程的话则直接再次获取成功

由于锁会被获取n次,那么只有锁在被释放同样的n次之后,该锁才算是完全释放成功

1、获取锁方法

 protected final boolean tryAcquire(int acquires) {
//获取当前线程
final Thread current = Thread.currentThread();
int c = getState();
//判断当前对象是否被持有
if (c == 0) {
//...略
}
//若被持有 判断锁是否是当前线程 可重入锁的关键代码
else if (current == getExclusiveOwnerThread()) {
//计数加1 返回
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
//不是当前线程持有 执行
return false;
}

每次如果获取到的都是当前线程这里都会计数加1

释放锁

protected final boolean tryRelease(int releases) {
//每次释放都减1
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
//等于0才释放锁成功
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}

如果锁被获取n次,也要释放了n次,只有完全释放才会返回false

ReentrantLock可重入锁、公平锁非公平锁区别与实现原理的更多相关文章

  1. Java中的常见锁(公平和非公平锁、可重入锁和不可重入锁、自旋锁、独占锁和共享锁)

    公平和非公平锁 公平锁:是指多个线程按照申请的顺序来获取值.在并发环境中,每一个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个就占有锁,否者就会加入到等待队列中,以 ...

  2. ReentrantLock——可重入锁的实现原理

    一. 概述 本文首先介绍Lock接口.ReentrantLock的类层次结构以及锁功能模板类AbstractQueuedSynchronizer的简单原理,然后通过分析ReentrantLock的lo ...

  3. JUC 一 ReentrantLock 可重入锁

    java.util.concurrent.locks ReentrantLock即可重入锁,实现了Lock和Serializable接口 ReentrantLock和synchronized都是可重入 ...

  4. J.U.C之ReentrantLock 可重入锁

    * A reentrant mutual exclusion {@link Lock} with the same basic * behavior and semantics as the impl ...

  5. Java并发包源码学习系列:ReentrantLock可重入独占锁详解

    目录 基本用法介绍 继承体系 构造方法 state状态表示 获取锁 void lock()方法 NonfairSync FairSync 公平与非公平策略的差异 void lockInterrupti ...

  6. ReentrantLock可重入锁——源码详解

    开始这篇博客之前,博主默认大家都是看过AQS源码的~什么居然没看过猛戳下方 全网最详细的AbstractQueuedSynchronizer(AQS)源码剖析(一)AQS基础 全网最详细的Abstra ...

  7. ReenTrantLock可重入锁(和synchronized的区别)总结

    ReenTrantLock可重入锁(和synchronized的区别)总结 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也 ...

  8. ReenTrantLock可重入锁和synchronized的区别

    ReenTrantLock可重入锁和synchronized的区别 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入 ...

  9. ReentrantLock可重入锁的理解和源码简单分析

    import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; /** * @author ...

  10. Java多线程系列--“JUC锁”05之 非公平锁

    概要 前面两章分析了"公平锁的获取和释放机制",这一章开始对“非公平锁”的获取锁/释放锁的过程进行分析.内容包括:参考代码获取非公平锁(基于JDK1.7.0_40)释放非公平锁(基 ...

随机推荐

  1. Redis-技术专区-帮从底层彻底吃透RDB技术原理

    每日一句 低头是一种能力,它不是自卑,也不是怯弱,它是清醒中的嬗变.有时,稍微低一下头,或者我们的人生路会更精彩. 前提概要 Redis是一个的键-值(K-V)对的内存数据库服务,通常包含了任意个非空 ...

  2. C#使用异步需要注意的几个问题

    C#异步使用需要注意的几个问题1.异步方法如果只是对别的方法的简单的转发调用,没哟复杂的逻辑(比如等待A的结果,再调用B,等待A调用的返回值拿到内部做一些处理再返回),那么就可以去掉async关键字. ...

  3. 快速入门PaddleOCR,并试用其开发一个搜题小工具

    介绍 PaddleOCR 是一个基于百度飞桨的OCR工具库,包含总模型仅8.6M的超轻量级中文OCR,单模型支持中英文数字组合识别.竖排文本识别.长文本识别.同时支持多种文本检测.文本识别的训练算法. ...

  4. etcd学习(8)-etcd中Lease的续期

    etcd中的Lease 前言 Lease Lease 整体架构 key 如何关联 Lease Lease的续期 过期 Lease 的删除 checkpoint 机制 总结 参考 etcd中的Lease ...

  5. 20210816 你相信引力吗,marshland,party?,半夜

    考场 第一眼都不可做 T1 长得就像单调栈/单调队列,推了推性质发现优弧.劣弧都合法的点对很好处理,其他情况只在一种情况合法,那么开两个单调队列分别统计距离 \(\le\frac2n,>\fra ...

  6. FastAPI(1)- 简单介绍

    前言 为啥要学它呢,因为学 Flask 的时候发现有人更推荐它代替 Flask,看了下介绍,感觉很强,而且也能拿来做平台,当然学起来!卷起来! 为什么要使用 FastAPI ? 日渐没落的是后端 HT ...

  7. Jenkins(8)- CentOS 7.x 通过yum安装jenkins

    如果想从头学起Jenkins的话,可以看看这一系列的文章哦 https://www.cnblogs.com/poloyy/category/1645399.html 下载rpm包 sudo wget ...

  8. netfilter框架之hook点

    1. Netfilter中hook的所在位置 当网络上有数据包到来时,由驱动程序将数据包从网卡内存区通过DMA转移到设备主存区(内存区), 之后触发中断通知CPU进行异步响应,之后ip_rcv函数会被 ...

  9. Redis-初见

    目录 启动and连接 JRedis 宝塔 Redis.conf RDB AOF(Append Only File) 发布和订阅 主从复制 一主二从 复制原理 宕机后的手动配置主机 哨兵模式 Redis ...

  10. C# 下载远程http文件到本地

    System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();   ...