1.ReentrantLock简介

理解了AQS,ReentrantLock理解起来其实就没有什么难度了。ReentrantLock,可重入锁。它可以等同于
synchronized的使用,但是ReentrantLock提供了比synchronized更强大、灵活的锁机制,可以减少死锁发
生的概率。

2.ReentrantLock继承关系


Lock中的方法: 主要提供了获取锁、尝试获取锁、释放锁、条件锁等几个方法。

3.源码分析

3.1 ReentrantLock内部类

ReentrantLock内部类有三个:Sync实现了AQS,NonfairSync 实现了Sync,用于获取非公平锁,FairSync 实现
了Sync用于获取公平锁。

abstract static class Sync extends AbstractQueuedSynchronizer
static final class NonfairSync extends Sync
static final class FairSync extends Sync
 //ReentrantLock只有一个Sync属性private final Sync sync;//默认构造函数:非公平锁public ReentrantLock() {sync = new NonfairSync();}//根据fair判断初始化公平锁还是非公平锁public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();}

3.2 非公平锁的获取

平时使用ReentrantLock的方法:

 ReentrantLock lock = new ReentrantLock();try{lock.lock();}catch(Exception e){.....}finally{lock.unlock();}

先来看看lock()方法

 public void lock() {//非公平锁的获取sync.lock();}
 final void lock() {//先CAS操作AQS的state成功,则表示获取锁if (compareAndSetState(0, 1))//将独占线程设置为当前线程setExclusiveOwnerThread(Thread.currentThread());else//调用AQS的acquire方法获取锁acquire(1);}

acquire()函数在AQS分析过,这里就不再啰嗦了:

 public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}

但是得说一说tryAcquire(arg)函数,Sync类有一个nonfairTryAcquire(acquires)方法,这个正是tryAcquire(arg)的实现函数。

 protected final boolean tryAcquire(int acquires) {//调用Sync类的方法return nonfairTryAcquire(acquires);}
   final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();//1.state==0表示锁未被其他线程获取,获取成功则返回trueif (c == 0) {if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}//2.如果锁已经被获取,判断是否是自己获取的,若是,则重入返回trueelse if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}//3.没有获取到锁返回falsereturn false;}

Reentrant的tryAcquire方法做的事情其实比较简单:

  1. 第一步先判断锁是否被获取过,若是则执行第二步;若否则尝试获取,如果获取成功则直接返回true
  2. 第二步判断获取锁的是否是当前线程,若是,则重入并返回true;否则直接返回false

非公平锁的整个获取流程:

3.3 公平锁的获取

非公平锁和公平锁的实现其实就是tryAcquire方法的不同

public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}
 protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();//查看当前状态变量int c = getState();if (c == 0) {// 如果没有其它线程在排队,那么当前线程尝试更新state的值为1// 如果成功了,则说明当前线程获取了锁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;}
     public final boolean hasQueuedPredecessors() {//判断是否有其他线程在排队获取锁Node t = tail; // Read fields in reverse initialization orderNode h = head;Node s;return h != t &&((s = h.next) == null || s.thread != Thread.currentThread());}

3.4 获取公平锁和非公平锁的区别

  1. 非公平锁上来就先CAS操作尝试获取锁,如果成功就获取到了锁。
  2. 非公平锁在tryAcquire获取锁时,没有检查是否前面有排队的线程,直接上去获取锁才不管别人有没有排队。

3.5 tryLock()方法

tryLock获取非公平锁

 public boolean tryLock() {return sync.nonfairTryAcquire(1);}

尝试获取一次锁,成功了就返回true,没成功就返回false,不会继续尝试。

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) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}

3.6 tryLock(long time, TimeUnit unit)方法

tryAcquireNanos在AQS那一篇博客已经说过,这里就不在赘述。

public boolean tryLock(long timeout, TimeUnit unit)throws InterruptedException {return sync.tryAcquireNanos(1, unit.toNanos(timeout));}

3.7 unlock()方法

**锁的释放在AQS那一篇也说过。具体看看tryRelease()**方法的实现:

public void unlock() {sync.release(1);}
protected final boolean tryRelease(int releases) {//重入锁调用多少次lock(),就要调用多少次unlock()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;}

4.未完待续

下一篇将讲述Reentrant的条件锁部分,并分析下Reentrant和Synchronized的区别。

  1. 为什么ReentrantLock默认采用的是非公平模式?
    答:因为非公平模式获取锁的效率比公平模式要高,非公平模式一上来就获取锁。tryAcquire方法也是一上来就获取锁,并不在乎是否有前面有排队等待的线程存在。少了排队导致的阻塞/唤醒过程,并且减少了线程频繁的切换带来的性能损耗。

  2. 非公平模式有什么弊端?
    答:会导致线程饥饿,有些线程可能一直都获取不到锁。

参考

死磕 java同步系列之ReentrantLock源码解析

ReentrantLock源码分析(一)相关推荐

  1. JUC AQS ReentrantLock源码分析

    Java的内置锁一直都是备受争议的,在JDK 1.6之前,synchronized这个重量级锁其性能一直都是较为低下,虽然在1.6后,进行大量的锁优化策略,但是与Lock相比synchronized还 ...

  2. Java并发编程-ReentrantLock源码分析

    一.前言 在分析了 AbstractQueuedSynchronier 源码后,接着分析ReentrantLock源码,其实在 AbstractQueuedSynchronizer 的分析中,已经提到 ...

  3. ReentrantLock源码分析

    ReentrantLock源码分析 前言 最近公司比较忙,整天忙着做项目.做需求,感觉整个人昏昏沉沉的,抬头看天空感觉都是灰色的~~,其实是杭州的天本来就是这个颜色,手动滑稽`~(^o^)/~`.废话 ...

  4. Java8 ReentrantLock 源码分析

    一.ReentrantLock 概述 1.1 ReentrantLock 简介 故名思义,ReentrantLock 意为可重入锁,那么什么是可重入锁呢?可重入意为一个持有锁的线程可以对资源重复加锁而 ...

  5. Java并发编程 ReentrantLock 源码分析

    ReentrantLock 一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大. 这个类主要基于AQS(Abst ...

  6. 【ReentrantLock源码分析】1.xdb中的使用 2.获取和阻塞(阻塞前的一些死心不改)的源码

    1.xdb中的使用例子 在xdb中,我们大概执行业务时的流程简化如下: package org.example.testReentrantLock;import java.util.concurren ...

  7. 源码篇:ReentrantLock 源码分析上篇

    文章目录 引言 整体结构 公平锁和非公平锁的差异 非公平锁 NonfairSync acquire,锁获取流程 tryAcquire(1) addWaiter 入队流程 acquireQueued 排 ...

  8. ReentrantLock 源码分析

    ReentrantLock简单使用demo如下: Lock lock = new ReentrantLock(); lock.lock(); try {//业务逻辑 } finally {lock.u ...

  9. 【java】java ReentrantLock 源码详解

    文章目录 1.概述 2.问题 3.ReentrantLock源码分析 3.1 类的继承关系 3.2 类的内部类 3.2.1 Sync类 3.2.2 NonfairSync类 3.2.3 FairSyn ...

最新文章

  1. python调用其他程序或脚本方法(转)
  2. 5分绩点转4分_工作复盘|因为这5点,4月份目标没完成
  3. myid文件缺失导致zookeeper无法启动(myid file is missing)
  4. linux后台执行脚本(产生日志和不产生日志)(大神请留言)
  5. shell脚本显示颜色的设置
  6. 关于Fluent瞬态计算你必须掌握的3个技巧
  7. 红米k20适配android q,比谷歌还快,红米K20 PRO首发安卓Q稳定版,只有华为心里苦...
  8. [CSP-J2019] 加工零件
  9. 黑马程序员java学习笔记——正则表达式、反射
  10. 桌面放大镜、演示工具推荐——ZoomIt
  11. 系统地学习打字(个人见解)
  12. 免费天气API,全国天气 JSON API接口,可以获取五天的天气预报
  13. 电路与电子3.2.2PNP型三极管与恒流充电源
  14. AngularJs实现增加订单、批量发货
  15. echarts关系图/力导向动态图(地图经纬度定位)
  16. 爬虫练习--爬取股票数据
  17. 主机与虚拟机之间传输文件—Xshell安装与使用教程
  18. vue3中不支持filters过滤器
  19. TweenLiteamp;amp;amp;amp;amp;amp;TweenMax系列(一)
  20. AI视频智能分析技术与应用(一)

热门文章

  1. 清除微信浏览器缓存问题
  2. ios含有支付_苹果APP Store审核提示包含第三方支付Alipay被拒
  3. 【电子文件制作攻略】(仅供参考)
  4. 批量返款系统,Sass聚合支付宝、微信,0手续费的技术方案
  5. SQL语句的内连接,外连接,左连接,右连接,全连接详解例子
  6. 十款适用于Pro Tools的笔记本电脑2022年8月
  7. vue模拟触发另一个按钮点击事件
  8. PB triggerevent函数
  9. 【转】搜狗测试经理分享
  10. go-elasticsearch 官方包操作合集