ReentrantLock之AQS原理与源码详解

ReentrantLock和AQS的关系


ReentrantLock使用

图片描述

AbstractQueuedSynchronizer,抽象队列同步器;给你们画一个图先,看一下ReentrantLock和AQS之间的关系。
图片描述源码分析

AbstractQueuedSynchronizer为ReentrantLock的静态内部类
图片描述post

lock()源码分析

图片描述

二、默认为非公平锁
图片描述spa

三、最终会调用AbstractQueuedSynchronizer子类NonfairSync.lock()方法;
图片描述
lock()方法作了什么事呢?
首先须要知道AQS会维护两个变量state(初始值0)、exclusiveOwnerThread(初始值null),源码以下,记录线程状态与当前加锁线程
图片描述线程

图片描述

线程1跑过来调用ReentrantLock的lock()方法尝试进行加锁,这个加锁的过程,直接就是用CAS操做将state值从0变为1。
若是以前没人加过锁,那么state的值确定是0,此时线程1就能够加锁成功。
一旦线程1加锁成功了以后,就能够设置当前加锁线程是本身。因此你们看下面的图,就是线程1跑过来加锁的一个过程。
图片描述队列

可重入锁

state记录加锁次数,为0时释放锁图片

锁的互斥是如何实现的?

线程2跑过来一下看到,哎呀!state的值不是0啊?因此CAS操做将state从0变为1的过程会失败,由于state的值当前为1,说明已经有人加锁了!
接着线程2会看一下,是否是本身以前加的锁啊?固然不是了,“加锁线程”这个变量明确记录了是线程1占用了这个锁,因此线程2此时就是加锁失败。
接着,线程2会将本身放入AQS中的一个等待队列,由于本身尝试加锁失败了,此时就要将本身放入队列中来等待,等待线程1释放锁以后,本身就能够从新尝试加锁了
因此你们能够看到,AQS是如此的核心!AQS内部还有一个等待队列,专门放那些加锁失败的线程!
一样,给你们来一张图,一块儿感觉一下:
图片描述
源码
线程2进来加锁失败后,会进入等待队列;等待队列为链表
图片描述
图片描述
图片描述
接着,线程1在执行完本身的业务逻辑代码以后,就会释放锁!他释放锁的过程很是的简单,就是将AQS内的state变量的值递减1,若是state值为0,则完全释放锁,会将“加锁线程”变量也设置为null!
整个过程,参见下图:
图片描述get

释放锁源码:

LockSupport.unpark(s.thread);
图片描述
图片描述
接下来,会从等待队列的队头唤醒线程2从新尝试加锁。
好!线程2如今就从新尝试加锁,这时仍是用CAS操做将state从0变为1,此时就会成功,成功以后表明加锁成功,就会将state设置为1。
此外,还要把“加锁线程”设置为线程2本身,同时线程2本身就从等待队列中出队了。
最后再来一张图,你们来看看这个过程。
图片描述同步

Node存储等待线程队列

图片描述

参考资料https://juejin.im/post/5c07e5...源码

相关文章
相关标签/搜索