1.ReentrantLock是基于AQS实现的一种重入锁。

2.先介绍下公平锁/非公平锁

公平锁

  • 公平锁是指多个线程按照申请锁的顺序来获取锁。

非公平锁

  • 非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。

3.重入锁/不可重入锁

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

不可重入锁:不可重入锁,与可重入锁相反,不可递归调用,递归调用就发生死锁。

4.统一入口

 //获取锁。
@Override
public void lock() {
sync.lock();
} //获取锁,响应中断
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly();
} //仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
@Override
public boolean tryLock() {
return sync.nonfairTryAcquire();
} //如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被 中断,则获取该锁。
@Override
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(, unit.toNanos(timeout));
} //试图释放此锁。
@Override
public void unlock() {
sync.release();
}

ReentrantLock默认是非公平模式,可以通过构造函数指定模式。

/**
* 构造函数,默认非公平锁
*/
public ReentrantLock() {
sync = new NonfairSync();
} /**
* 构造函数,通过布尔参数设置是否是公平锁
* @param fair
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}

4.非公平模式的加锁和解锁

加锁:

//获取锁。
@Override
public void lock() {
sync.lock();
}

然后调用NonfairSync的lock方法:

/**
* 加锁
*/
@Override
final void lock() {
//以cas方式尝试将AQS中的state从0更新为1
if (compareAndSetState(, )) {
//获取锁成功则将当前线程标记为持有锁的线程,然后直接返回
setExclusiveOwnerThread(Thread.currentThread());
} else {
acquire();
}
}

如果设置state失败,则调用NonfairSync的tryAcquire方法

@Override
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}

然后调用Sync的nonfairTryAcquire方法:

/**
* 非公平模式的情况下获取同步状态
* @param acquires
* @return
*/
final boolean nonfairTryAcquire(int acquires) {
//获取当前线程实例
final Thread current = Thread.currentThread();
//获取同步state变量的值,即当前锁被重入的次数
int c = getState();
//state为0,说明当前锁未被任何线程持有
if (c == ) {
//以cas方式获取锁
if (compareAndSetState(, acquires)) {
//将当前线程标记为持有锁的线程
setExclusiveOwnerThread(current);
//获取锁成功,非重入
return true;
}
//当前线程就是持有锁的线程,说明该锁被重入了,实现重入
} else if (current == getExclusiveOwnerThread()) {
//计算state变量要更新的值
int nextc = c + acquires;
if (nextc < ) // overflow
throw new Error("Maximum lock count exceeded");
//非同步方式更新state值
setState(nextc);
//获取锁成功,重入
return true;
}
//尝试获取锁失败
return false;
}

这边体现了锁的重入,用state的次数表示锁被线程重入了state次。

else if (current == getExclusiveOwnerThread()) {
//计算state变量要更新的值
int nextc = c + acquires;
if (nextc < ) // overflow
throw new Error("Maximum lock count exceeded");
//非同步方式更新state值
setState(nextc);
//获取锁成功,重入
return true;
}

解锁

//试图释放此锁。
@Override
public void unlock() {
sync.release();
}

然后调用Sync的tryRelease方法:

/**
* 释放同步状态
* @param releases
* @return
*/
@Override
protected final boolean tryRelease(int releases) {
//计算待更新的state值
int c = getState() - releases;
//判断当前线程是否独占
if (Thread.currentThread() != getExclusiveOwnerThread()) {
throw new IllegalMonitorStateException();
}
//是否释放同步状态成功的标志
boolean free = false;
//待更新的state值为0,说明持有锁的线程未重入,一旦释放锁其他线程将能获取
if (c == ) {
free = true;
//清除锁的持有线程标记
setExclusiveOwnerThread(null);
}
//更新state值
setState(c);
return free;
}
 锁的最终释放要去锁对于获取进行计数自增,计算表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数为0时表示已经释放成功。

5.公平模式的加锁和解锁

加锁:

@Override
protected final boolean tryAcquire(int acquires) {
//获取当前线程实例
final Thread current = Thread.currentThread();
//获取同步state变量的值,即当前锁被重入的次数
int c = getState();
//state为0,说明当前锁未被任何线程持有
if (c == ) {
/**
* 1.判断同步队列中当前节点是否有前驱节点
* 2. 以cas方式获取锁
*/
if (!hasQueuedPredecessors() &&
compareAndSetState(, acquires)) {
//将当前线程标记为持有锁的线程
setExclusiveOwnerThread(current);
return true;
}
//当前线程就是持有锁的线程,说明该锁被重入了,实现重入
} else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < )
throw new Error("Maximum lock count exceeded");
//非同步方式更新state值
setState(nextc);
//获取锁成功,重入
return true;
}
//尝试获取锁失败
return false;
}

对于非公平锁,只要cas设置同步状态成功,则表示当前线程获取了锁,而公平锁则不同,公平锁的获取增加了hasQueuedPredecessors的判断,即加入了判断同步队列中当前节点是否有前驱节点,

如果返回true,则表示有线程比当前线程更早滴请求获取锁,因此需要等待前驱线程获取并释放锁之后才能继续获取锁。

锁:同公平锁的解锁方式

 

 

ReentrantLock(重入锁)简单源码分析的更多相关文章

  1. ReentrantLock(重入锁)的源码解析

    转自:从源码角度彻底理解ReentrantLock(重入锁)](https://www.cnblogs.com/takumicx/p/9402021.html)) 公平锁内部是FairSync,非公平 ...

  2. 从源码角度彻底理解ReentrantLock(重入锁)

    目录 1.前言 2.AbstractQueuedSynchronizer介绍 2.1 AQS是构建同步组件的基础 2.2 AQS的内部结构(ReentrantLock的语境下) 3 非公平模式加锁流程 ...

  3. java并发系列(四)-----源码角度彻底理解ReentrantLock(重入锁)

    1.前言 ReentrantLock可以有公平锁和非公平锁的不同实现,只要在构造它的时候传入不同的布尔值,继续跟进下源码我们就能发现,关键在于实例化内部变量sync的方式不同,如下所示: /** * ...

  4. ReentrantLock 锁释放源码分析

    ReentrantLock 锁释放源码分析: 调用的是unlock 的方法: public void unlock() { sync.release(1); } 接下来分析release() 方法: ...

  5. java高并发系列 - 第12天JUC:ReentrantLock重入锁

    java高并发系列 - 第12天JUC:ReentrantLock重入锁 本篇文章开始将juc中常用的一些类,估计会有十来篇. synchronized的局限性 synchronized是java内置 ...

  6. JUC之线程池基础与简单源码分析

    线程池 定义和方法 线程池的工作时控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等待其他线程执行完成,再从队列中取出任 ...

  7. ReentrantLock(重入锁)以及公平性

    ReentrantLock(重入锁)以及公平性 标签(空格分隔): java NIO 如果在绝对时间上,先对锁进行获取的请求一定被先满足,那么这个锁是公平的,反之,是不公平的,也就是说等待时间最长的线 ...

  8. ReentrantLock重入锁详解

    1.定义 重入锁:能够支持一个线程对资源的重复加锁,也就是当一个线程获取到锁后,再次获取该锁时而不会被阻塞. 2.可重入锁的应用场景 2.1 如果已经加锁,则不再重复加锁,比如:交互界面点击后响应时间 ...

  9. Java多线程之ReentrantLock重入锁简介与使用教程

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6543947.html  我们知道,线程安全问题需要通过线程之间的同步来解决,而同步大多使用syncrhoize ...

随机推荐

  1. python 修饰器 最好的讲解

    Python的修饰器的英文名叫Decorator,修饰器就是对一个已有的模块做一些“修饰工作”,比如在现有的模块加上一些小装饰(一些小功能,这些小功能可能好多模块都会用到),但又不让这个小装饰(小功能 ...

  2. Scrapy学习-11-Selector对象使用

    Selector使用 使用背景 我需要使用类似spider项目中,response使用的xpath和css获取页面指定数据,但因为爬取页面较小我们不想创建一个spider项目时,就可以使用scrapy ...

  3. Codeforces 932 A.Palindromic Supersequence (ICM Technex 2018 and Codeforces Round #463 (Div. 1 + Div. 2, combined))

    占坑,明天写,想把D补出来一起写.2/20/2018 11:17:00 PM ----------------------------------------------------------我是分 ...

  4. Codeforces Gym101606 D.Deranging Hat (2017 United Kingdom and Ireland Programming Contest (UKIEPC 2017))

    D Deranging Hat 这个题简直了,本来想的是冒泡排序然后逆着输出来的,后来发现不对,因为题目上求的是最优解,而且冒泡的话,输出结果有的超出10000行了,所以就是把一开始的,排好序的字母标 ...

  5. L1-3. 情人节【求第2个、第14个人的名字,设置计数器并标记一下即可】

    L1-3. 情人节 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 以上是朋友圈中一奇葩贴:“2月14情人节了,我决定造福大家. ...

  6. 2017 ACM-ICPC 沈阳区域赛记录

    出发日 中午坐大巴前往萧山机场. 哇开心又可以坐飞机了 飞机延误了.在候机大厅里十分无聊,先用机场的电脑玩了会小游戏 然后偷偷切了2个水题 (什么编译器IDE都没有,只能记事本了) 飞机上什么东西都没 ...

  7. 板子-GOD BLESS ALL OF YOU

    字符串: KMP #include<cstdio> #include<cstring> ; ]; ]; int l1,l2; void get_next() { next[]= ...

  8. Hdoj 3506 Monkey Party

    Discription Far away from our world, there is a banana forest. And many lovely monkeys live there. O ...

  9. BZOJ1005明明的烦恼 Prufer + 分解質因數 + 高精度

    @[高精度, Prufer, 質因數分解] Description 自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在 任意两点间连线,可产生多 ...

  10. javascript 对象初探 (四)--- 内建对象之旅之Boolean

    var a = new Boolean() 我们要明白一点在这里的b是一个对象而不是一个基本数据类型的布尔值.如果想将b转化成基本数据类型的布尔值,我们可以调用她的valueof()方法(继承自Obj ...