详细讲解下Lock的底层原理(ReentrantLock的获得锁和释放锁)

【详细讲解下Lock的底层原理(ReentrantLock的获得锁和释放锁)】文章开头给大家几个关键字:计数值,双向链表,CAS+自旋
前言:什么是CAS?,什么是AQS?
CAS:全称Compare And Swap即比较并交换,他是解决多线程并行情况下使用锁而造成性能上的损耗的一种机制。
CAS:包含3个操作数:
V:内存位置
A:预期的原值(也就是原本值)
B:新的值。
若当前内存位置下的值与A相匹配,那么处理器自动将该位置的值改为B(就是一个替换操作)。若不匹配,那么不作任何操作。
差不多表示为CAS(A,B),这个等式只有两种情况,A的值被替换成B,A值不变。
AQS(全称AbstractQueuedSychronizer):是jdk提供的一套用于实现基于FIFO等待队列的堵塞锁与相关的同步器的一个同步框架。设计为一些可用原子int值来表示状态的同步器的基类,这里打星了!!
接下来是放图时间:在这里插入图片描述
详细讲解下Lock的底层原理(ReentrantLock的获得锁和释放锁)
文章图片

大家可以看下这个父子类关系,这里我们重点介绍ReentrantLock
再看下这个类里面有什么东西详细讲解下Lock的底层原理(ReentrantLock的获得锁和释放锁)
文章图片

竟然就一行代码,但是可以看出来,这里面的对象new的是一个叫NofairSync的非公平锁
介绍下什么是非公平锁:就是当有线程准备竞争锁的时候,他不会进入等待队列,而是首先去尝试自己去竞争那个锁,那么对于那些已经存在于等待队列的线程来说,是不是不公平??,所以这个就叫非公平锁。
言归正传,既然ReentrantLock的父类有个AQS,那么我们看下他的源码:详细讲解下Lock的底层原理(ReentrantLock的获得锁和释放锁)
文章图片

只截图了一部分。但是可以仔细看到第一个是不是一个叫Node的类?大家看到这里有没有感到很熟悉?那么再来一张图详细讲解下Lock的底层原理(ReentrantLock的获得锁和释放锁)
文章图片

从我圈起来的部分可以看出,Node是个双向链表!,对应了文章开头的关键字吧。
再看看最后一个圈起来的,int类型的state,在回顾下上文讲的AQS的一个原子int值来表示状态,那么这里的state就是所谓的锁的状态。
这里就做出一个小总结:锁的存储结构:双链表+int类型状态来实现。
注意:这里的变量都是有volatile修饰的,那么这些变量不就是同步的了?
那么Lock如何获取锁?前回顾下前面是不是new一个NonfairSyc对象?
看下这个类的源码详细讲解下Lock的底层原理(ReentrantLock的获得锁和释放锁)
文章图片

总的来说0代表获得锁失败,1代表成功。那么如果获取锁不成功,怎么办?
看下对应的else分支下面的acquire方法:看下他的源码:详细讲解下Lock的底层原理(ReentrantLock的获得锁和释放锁)
文章图片

说白了,通过CAS确保在线性安全的情况下,会将当前线程加到链表的地步
accquireQueued:如果获取锁成功,那么释放你当前的一个等待状态
否则失败,那么通过自旋的方式去不断的尝试获取锁详细讲解下Lock的底层原理(ReentrantLock的获得锁和释放锁)
文章图片
详细讲解下Lock的底层原理(ReentrantLock的获得锁和释放锁)
文章图片

(这里从别的博客借来的图,忘记在哪了)
Lock获得锁讲完了,那么Lock如何释放锁呢?详细讲解下Lock的底层原理(ReentrantLock的获得锁和释放锁)
文章图片

release调用的是下面的tryRelease详细讲解下Lock的底层原理(ReentrantLock的获得锁和释放锁)
文章图片

总结:

  1. lock的存储结构:双链表(Node)+int类型的状态值
  2. lock获得锁的过程:本质通过CAS来更改状态值(0,1)若线程没取到,则进入等待队列(Node)
  3. lock释放锁:修改状态值,调整等待的链表。

    推荐阅读