ReentrantLock 示例

  1. private ReentrantLock lock = new ReentrantLock(true);
  2. public void f(){
  3. try {
  4. lock.lock();
  5. //do something
  6. }
  7. finally {
  8. lock.unlock();
  9. }
  10. }

源码解析(公平锁-unlock流程)

ReentrantLock#unlock()

  1. public void unlock() {
  2. sync.release(1);
  3. }

AbstractQueuedSynchronizer#release(int arg)

  1. public final boolean release(int arg) {
  2. //尝试释放锁,只有当 state == 0 才会释放成功
  3. if (tryRelease(arg)) {
  4. //释放成功之后,查看head节点,如果head节点不为 null,并且,head节点不为0 (可能为 -1)
  5. Node h = head;
  6. if (h != null && h.waitStatus != 0)
  7. //unpark 线程
  8. unparkSuccessor(h);
  9. return true;
  10. }
  11. return false;
  12. }

ReentrantLock.Sync#tryRelease(int arg)

  1. protected final boolean tryRelease(int releases) {
  2. //state - releases,上锁之后,state > 0,所以释放锁要减掉
  3. int c = getState() - releases;
  4. //如果当前线程并不是持有锁的线程,不能乱释放锁,直接给你抛个异常
  5. if (Thread.currentThread() != getExclusiveOwnerThread())
  6. throw new IllegalMonitorStateException();
  7. //释放标志
  8. boolean free = false;
  9. //由于是可重入锁,所以当 c == 0 的情况下才真正释放完成
  10. if (c == 0) {
  11. free = true;
  12. //设置当前线程为空
  13. setExclusiveOwnerThread(null);
  14. }
  15. setState(c);
  16. return free;
  17. }

AbstractQueuedSynchronizer#unparkSuccessor(Node node)

  1. private void unparkSuccessor(Node node) {
  2. //获取head node节点的 waitStatus , < 0(-1) 就CAS 改回 0
  3. int ws = node.waitStatus;
  4. if (ws < 0)
  5. compareAndSetWaitStatus(node, ws, 0);
  6. //找到下一个节点
  7. Node s = node.next;
  8. //如果下一个节点为null,或者 已经取消抢锁了,继续往下找
  9. if (s == null || s.waitStatus > 0) {
  10. s = null;
  11. //从尾部向前遍历,如果 waitStatus<=0 就赋值给 s,这样保证最前边的一个waitStatus<=0的线程可以唤醒。
  12. for (Node t = tail; t != null && t != node; t = t.prev)
  13. if (t.waitStatus <= 0)
  14. s = t;
  15. }
  16. //如果下一个节点不为 null,直接 unpark 线程,对应代码就是AbstractQueuedSynchronizer#acquireQueued(Node node, int arg) 中 的for(;;),这样线程唤醒之后,就会尝试再去获取锁了。
  17. if (s != null)
  18. LockSupport.unpark(s.thread);
  19. }

总结

释放锁的流程比较简单,就是讲 state减去1,然后去队列里面找下一个节点,最后执行 unpark 方法唤醒线程。

ReentrantLock源码学习总结 (二)的更多相关文章

  1. 死磕 java同步系列之ReentrantLock源码解析(二)——条件锁

    问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等 ...

  2. Java并发之ReentrantLock源码解析(二)

    在了解如何加锁时候,我们再来了解如何解锁.可重入互斥锁ReentrantLock的解锁方法unlock()并不区分是公平锁还是非公平锁,Sync类并没有实现release(int arg)方法,这里会 ...

  3. java源码学习(二)Integer

    Integer类包含了一个原始基本类型int.Integer属性中就一个属性,它的类型就是int. 此外,这个类还提供了几个把int转成String和把String转成int的方法,同样也提供了其它跟 ...

  4. ReentrantLock源码学习总结 (一)

    [^ ]: 以下源码分析基于JDK1.8 ReentrantLock 示例 private ReentrantLock lock = new ReentrantLock(true); public v ...

  5. Java集合源码学习(二)ArrayList分析

    >>关于ArrayList ArrayList直接继承AbstractList,实现了List. RandomAccess.Cloneable.Serializable接口,为什么叫&qu ...

  6. Spring源码学习(二)AOP

    ----ProxyFactoryBean这个类,这是AOP使用的入口---- AOP有些特有的概念,如:advisor.advice和pointcut等等,使用或配置起来有点绕,让人感觉有些距离感,其 ...

  7. Java集合源码学习(二)ArrayList

    1.关于ArrayList ArrayList直接继承AbstractList,实现了List. RandomAccess.Cloneable.Serializable接口,为什么叫"Arr ...

  8. jQuery源码学习笔记二

    //添加实例属性和方法 jQuery.fn = jQuery.prototype = { // 版本,使用方式:$().jquery弹出当前引入的jquery的版本 jquery: core_vers ...

  9. Guava源码学习(二)Ordering

    基于版本:Guava 22.0 Wiki:Ordering 0. Ordering简介 Guava的Ordering提供了链式风格的比较器的实现,我们可以用Ordering轻松构建复杂的比较器. 1. ...

随机推荐

  1. Vue相关知识点记录

    1.安装 vue不支持ie8以下版本(无法模拟ECMAScript5特性),支持所有兼容ECMAScript5的浏览器. 浏览器安装Vue Devtools, 可以在更友好的界面中审查和调试Vue应用 ...

  2. js中 !==和 !=的区别是什么

    1.比较结果上的区别 !=返回同类型值比较结果. !== 不同类型不比较,且无结果,同类型才比较. 2.比较过程上的区别 != 比较时,若类型不同,会偿试转换类型. !== 只有相同类型才会比较. 3 ...

  3. jQuery的内部运行机制和原理

    jQuery的优点: jQuery是一个非常优秀的JavaScript库,与Prototype,YUI,Mootools等众多的Js类库相比,它剑走偏锋,从Web开发实用的角度出发,抛除了其它Lib中 ...

  4. Cheat Engine 人造指针

    打开游戏 查看内存区域 查看游戏当前使用的内存区域 下面这一段是游戏当前使用的内存区域,选择一片可以读写的内存区域 跳转到这片内存 查看是否有空余内存可以使用 使用空闲内存 我们选择0075DFD0开 ...

  5. MySQL-长事务详解

    前言:  『入门MySQL』系列文章已经完结,今后我的文章还是会以MySQL为主,主要记录下近期工作及学习遇到的场景或者自己的感悟想法,可能后续的文章不是那么连贯,但还是希望大家多多支持.言归正传,本 ...

  6. csv、json 文件读取

    1.CSV 文件存储 1.1 写入 简单示例 import csv with open('data.csv', 'a') as csvfile: writer = csv.writer(csvfile ...

  7. Nginx——跨域造成的504问题

    前言 前台域名和后台域名是两个不同不同的二级域名,访问的时候造成了跨域,出现了504错误 解决 修改Nginx配置,将超时的时间设置为1200秒 keepalive_timeout 1200; pro ...

  8. str = @"abc ""def"" ghi """"jkl"""" mn";

    namespace ConsoleQuotes { class Program { static void Main(string[] args) { string str = @"abc ...

  9. stm32软件编程的框架及注意事项——rtos篇

    0.通常,嵌入式软件(这里指单片机系统)的框架千变万化,有带rtos的,也有裸机的. 0.1.写过带系统的,也写过裸机的,这里总结一下两个类型的框架,记录下自己的心得,主要是文字描述,框架图可以后期添 ...

  10. 开源项目(9-0)综述--基于深度学习的目标跟踪sort与deep-sort

    基于深度学习的目标跟踪sort与deep-sort https://github.com/Ewenwan/MVision/tree/master/3D_Object_Detection/Object_ ...