ReentrantLock源码分析--jdk1.8
JDK1.8
ArrayList源码分析--jdk1.8
LinkedList源码分析--jdk1.8
HashMap源码分析--jdk1.8
AQS源码分析--jdk1.8
ReentrantLock源码分析--jdk1.8
ReentrantLock概述
1. ReentrantLock是独占锁。
2. ReentrantLock分为公平模式和非公平模式。
3. ReentrantLock锁可重入(重新插入)
ReentrantLock源码分析
/**
* @since 1.5
* @author Doug Lea
* 独占锁 --默认使用非公平锁模式
* 可重入
*
* synchronized锁通过监视器Monitor来实现同步,monitorenter加锁,monitorexit解锁。
* synchronized是可重如的非公平锁
* synchronized在jdk1.6进行优化,添加了偏向锁、轻量级锁、重量级锁,关键字之锁的升级(偏向锁->轻量级锁->重量级锁)
* 偏向锁:当线程访问同步块时,会使用 CAS 将线程 ID 更新到锁对象的 Mark Word 中,如果更新成功则获得偏向锁,并且之后每次进入这个对象锁相关的同步块时都不需要再次获取锁了。
* 轻量级锁:如果同步对象为无锁状态时,直接尝试CAS更新Mark Word添加锁,如果成功,获得锁,失败升级为重量级锁
* 重量级锁:是指当锁是轻量级锁时,当自旋的线程自旋了一定的次数后,还没有获取到锁,就会进入阻塞状态,该锁升级为重量级锁,重量级锁会使其他线程阻塞,性能降低。
* 在使用 CAS 时,如果操作失败,CAS 会自旋再次尝试。由于自旋是需要消耗 CPU 资源的,所以如果长期自旋就白白浪费了 CPU。JDK1.6加入了适应性自旋:如果某个锁自旋很少成功获得,那么下一次就会减少自旋。
*/
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
private final Sync sync;
/**
* Sync内部类,继承AQS,实现独占锁模式,作为基础内部类
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* 加锁
*/
abstract void lock();
/**
* 判断 reentranLock 状态 是否被锁住(state ?= 0)
* <p>如果没被锁住尝试 原子性上锁 失败返回false</>
* <p>如果被锁住 判断是否是当前线程持有锁(重入锁的实现) 如果是 state + 1
* (信号量 记录该线程持有锁的次数。 该线程每次释放所 信号量 -1。 信号量为零 代表 锁被真正释放)</>
* <p>else 返回false</p>
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread(); //获取到当前的线程
int c = getState(); //获取锁的状态
if (c == 0) { //目前没有人在占有锁 如果锁已被经释放 再次尝试获取锁
if (compareAndSetState(0, acquires)) { //直接尝试把当前只设置成1,如果成功,把owner设置自己,并且退出
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) { // 如果当前线程为锁的拥有者
int nextc = c + acquires; //这里就是重入锁的概念,如果还是自己,则进行加1操作,因为释放和获取一定要是对等的
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc); // 累加 state 的值 此段代码 实现了重入锁
return true;
}
return false; //当前锁被其他线程占用,退出。
}
/**
* 释放锁,默认releases传1
*/
protected final boolean tryRelease(int releases) {
int c = getState() - releases; //获取当前的锁的状态并且减1,因为要释放锁
if (Thread.currentThread() != getExclusiveOwnerThread()) //如果当前自己不是锁的持有者,只有自己才能释放锁
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) { //释放成功
free = true;
setExclusiveOwnerThread(null);
}
setState(c); //重新设置成状态
return free;
}
/**
* 如果当前线程独占着锁,返回true
*/
protected final boolean isHeldExclusively() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}
/**
* 条件队列
*/
final ConditionObject newCondition() {
return new ConditionObject();
}
/**
* 返回锁的拥有者的线程
* 当前状态为0返回null,说明在等待中
* 当前状态不为0返回当前线程
*/
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
/**
* 当前线程占着锁返回 state,否则返回0
*/
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
/**
* state状态不为0标识上锁,为0表示在等待,不上锁
*/
final boolean isLocked() {
return getState() != 0;
}
/**
* 反序列化
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
/**
* 构造方法,默认选择非公平锁
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* 构造方法,true公平锁,false非公平锁
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
ReentrantLock继承和实现分析
ReentrantLock implements Lock
Sync extends AbstractQueuedSynchronizer
1.ReentrantLock实现Lock接口,Lock接口定义了加锁、条件队列、解锁、加锁(中断异常)
2.Sync继承AQS抽象类,实现了独占锁,作为基础内部类ReentrantLock源码分析
1. FairSync公平锁--内部类
/**
* 公平锁
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
2. NonfairSync非公平锁--内部类
/**
* 非公平锁的同步对象
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
* 非公平锁,每次先去获取对象,所以不排队,不公平
*/
final void lock() {
// 通过原子操作 改变上锁状态
if (compareAndSetState(0, 1)) // 变更成功,说明获取锁成功
setExclusiveOwnerThread(Thread.currentThread()); // 设置持有者为当前线程
else //变更失败
acquire(1); //尝试以独占模式获取锁,如果失败加入node节点到队列中
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
/**
* 是否有等待线程
*/
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
/**
* 是否有等待线程
*/
public final boolean hasQueuedThreads() {
return head != tail;
}
ReentrantLock总结
1)ReentrantLock是可重入的公平/非公平模式的独占锁。
2)ReentrantLock公平锁往往没有非公平锁的效率高,但是,并不是任何场景都是以TPS作为唯一指标,公平锁
能够减少“饥饿”发生的概率,等待越久的请求越能够得到优先满足。
ReentrantLock源码分析--jdk1.8的更多相关文章
- JUC AQS ReentrantLock源码分析
警告⚠️:本文耗时很长,先做好心理准备,建议PC端浏览器浏览效果更佳. Java的内置锁一直都是备受争议的,在JDK1.6之前,synchronized这个重量级锁其性能一直都是较为低下,虽然在1.6 ...
- ReentrantLock 源码分析以及 AQS (一)
前言 JDK1.5 之后发布了JUC(java.util.concurrent),用于解决多线程并发问题.AQS 是一个特别重要的同步框架,很多同步类都借助于 AQS 实现了对线程同步状态的管理. A ...
- Java并发编程之ReentrantLock源码分析
ReentrantLock介绍 从JDK1.5之前,我们都是使用synchronized关键字来对代码块加锁,在JDK1.5引入了ReentrantLock锁.synchronized关键字性能比Re ...
- Java并发编程-ReentrantLock源码分析
一.前言 在分析了 AbstractQueuedSynchronier 源码后,接着分析ReentrantLock源码,其实在 AbstractQueuedSynchronizer 的分析中,已经提到 ...
- java多线程---ReentrantLock源码分析
ReentrantLock源码分析 基础知识复习 synchronized和lock的区别 synchronized是非公平锁,无法保证线程按照申请锁的顺序获得锁,而Lock锁提供了可选参数,可以配置 ...
- ArrayList源码分析--jdk1.8
ArrayList概述 1. ArrayList是可以动态扩容和动态删除冗余容量的索引序列,基于数组实现的集合. 2. ArrayList支持随机访问.克隆.序列化,元素有序且可以重复. 3. ...
- JUC之ReentrantLock源码分析
ReentrantLock:实现了Lock接口,是一个可重入锁,并且支持线程公平竞争和非公平竞争两种模式,默认情况下是非公平模式.ReentrantLock算是synchronized的补充和替代方案 ...
- ReentrantLock 源码分析从入门到入土
回答一个问题 在开始本篇文章的内容讲述前,先来回答我一个问题,为什么 JDK 提供一个 synchronized 关键字之后还要提供一个 Lock 锁,这不是多此一举吗?难道 JDK 设计人员都是沙雕 ...
- Java并发系列[5]----ReentrantLock源码分析
在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...
随机推荐
- Bzoj 1997 [Hnoi2010]Planar题解
1997: [Hnoi2010]Planar Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 2224 Solved: 824[Submit][Stat ...
- codeblocks出现'to_string' was not declared in this scope 的问题,用g++11编译环境
在将数字转化为字符串时使用to_string()竟然出现了'to_string' was not declared in this scope,我头文件用的万能头文件肯定没问题,而这个函数在其他的CB ...
- 学习2:总结# 1.while # 2.字符串格式化 # 3.运算符 # 4.编码初始
目录 1.while循环 -- 死循环 2.字符串格式化: 3.运算符 4.编码 1.while循环 -- 死循环 while 条件: 循环体 打断死循环: break -- 终止当前循环 改变条件 ...
- TigerGraph入门
测试机器配置 1G内存,1个核,CentOS Linux release 7.4.1708 (Core)的云主机,一块50G HDD的云主机. 1. 安装 下载了目前最新的开发者版本,下载链接:htt ...
- DML语言DDL
DML(data manipulation language): 它们是SELECT.UPDATE.INSERT.DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据进行操作的语言 . D ...
- spring配置文件比较全的约束
个人总结:Spring的配置文件applicationContext.xml约束文件.全面约束 <?xml version="1.0" encoding="utf- ...
- FJNUOJ 1002 画葫芦。。
画图就是..找..规..律 #include <iostream>using namespace std;int main(){ int T; cin>>T; while(T- ...
- LiteDB源码解析系列(4)跳表基本原理
LitDB里面索引的数据结构是用跳表来实现的,我知道的开源项目中使用跳表的还包括Redis,大家可以上网搜索关于Redis的跳表功能的实现.在这一章,我将结合LiteDB中的示例来讲解跳表. 1.跳表 ...
- ArcGIS API For JavaScript 开发(二)基础地图
有了开发环境,接下来的就是实践了,实践是检验真理的唯一标准! 多多练习,不要觉得自己能够想的出来就万事大吉了,还是得动手做才是最好的检验自己的能力. 基础地图,本节将通过arcgis api for ...
- IT技术人员的自我修养
1. 前言 在IT领域摸爬滚打多年,从一个普通程序员到技术主管,到技术经理,再到技术总监,踩过不少坑.加过不少班,也背过不少锅,在提升自身技术能力与管理能力的同时,也一直在思考,作为IT ...