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. FNV哈希算法【转】

    转自:http://blog.csdn.net/hustfoxy/article/details/23687239 由来:FNV哈希算法全名为Fowler-Noll-Vo算法,是以三位发明人Glenn ...

  2. linux下 open fopen区别

    open是linux下的底层系统调用函数,fopen与freopen c/c++下的标准I/O库函数,带输入/输出缓冲.linxu下的fopen是open的封装函数,fopen最终还是要调用底层的系统 ...

  3. php自动获取字符串编码函数mb_detect_encoding

    当在php中使用mb_detect_encoding函数进行编码识别时,很多人都碰到过识别编码有误的问题,例如对与GB2312和UTF- 8,或者UTF-8和GBK(这里主要是对于cp936的判断), ...

  4. Day 20 迭代器、生成器

    一. 迭代器 1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退) 2.可迭代对象:实 ...

  5. Tomcat是怎么工作的(1) -- 开篇

    这是一个系列文章的第一篇. 标题还是费了点脑子才确定的,起什么名字比较好呢.Tomcat工作原理?深入浅出Tomcat运行机制?从零开始研究Tomcat?Tomcat是怎么运行起来的?Tomcat是如 ...

  6. ASP.NET Core 依赖注入基本用法

    ASP.NET Core 依赖注入 ASP.NET Core从框架层对依赖注入提供支持.也就是说,如果你不了解依赖注入,将很难适应 ASP.NET Core的开发模式.本文将介绍依赖注入的基本概念,并 ...

  7. Vijos——P1137 组合数

    https://vijos.org/p/1137 描述 组合公式 C=N!/(M!*(N-M)!). 问题是求 C 中不同的质因子的个数例如 N=7, M=4. C=7!/(3!*4!)=5040/( ...

  8. 着陆攻击LAND Attack

    着陆攻击LAND Attack   着陆攻击LAND Attack也是一种拒绝服务攻击DOS.LAND是Local Area Network Denial的缩写,意思是局域网拒绝服务攻击,翻译为着陆攻 ...

  9. 一个能让你了解所有函数调用顺序的Android库

    http://mobile.51cto.com/android-536059.htm 原理 本库其实并没有什么黑科技,本库也没有java代码,核心就是2个build.gradle中的task.首先,原 ...

  10. OpenSceneGraph FAQ 【转】

    1.地球背面的一个点,计算它在屏幕上的坐标,能得到吗? 不是被挡住了吗? 答:计算一个空间点的屏幕坐标,使用osgAPEx::GetScreenPosition函数.当空间点处于相机视空间内(不管它是 ...