JUC-lock&AQS源码分析

学习三板斧

  • 1.理论
  • 2.实操
  • 3.小总结

一.LOCK

0.阻塞和唤醒线程的方法

image.png

1.object中的wait和notify

image.png

image.png

2.lock中的await和signal

image.png

3.lockSupport

image.png
image.png
image.png

二.AQS (抽象队列同步器)

image.png
image.png

和AQS有关的对外api


image.png
image.png
image.png
image.png
image.png
image.png

共享资源被占用:


image.png
image.png
image.png
image.png
image.png

AQS内部体系结构

image.png
image.png
image.png

Node类

image.png
image.png

每个node都存放一个线程


image.png

AQS源码解读

image.png
image.png
image.png
image.png
image.png
image.png
image.png

案例银行业务

走非公平锁


image.png

1.A线程没进入之前


image.png

2.A进入之后


image.png

3.B即将进入,发现A已经占用了,走else分支


image.png
image.png
image.png

可重入锁的体现

4.B返回false后取反,继续走其他方法--addWaiter()


image.png
image.png

B第一次进来 tail尾节点是null,因此 走enq()方法

image.png

初始化时,是直接new 一个Node节点 (通过CAS方式)

image.png
image.png

对应588行代码

注意:因为是
for(;;) 所以,此时还没返回, 此时才走else


image.png

(t是哨兵节点)


image.png

B成功入队(注意,A获取锁后,B进去等待队列,而等待队列的第一个node不是B而是一个哨兵节点,加入哨兵节点是为了简化操作)

5.C加入队列(由于有B已经在了,所以没进入enq()方法)


image.png

image.png
image.png
image.png
  1. acquireQueued()分析


    image.png
image.png

尝试将第一个节点(此时是B)再去获取锁,失败 走else

image.png
image.png

连续两次尝试都失败后,调用park,挂起等待


image.png

当C过来次也是如此

image.png

此时 parkAndCheckInterrupt()还未结束,就挂起;

方法描述:


image.png
image.png

7.A准备离开,调用unlock方法-->会调用sync的realse方法

image.png
image.png

A释放后,返回true,此时走1261行代码

image.png

走unparkSuccessor()


image.png

注意图有误:此时B节点的waitStatus = -1,由于C加入的缘故

8.出队
B被唤醒


image.png

B抢占成功后走864行


image.png
image.png
image.png

把原来的B变成哨兵节点,且不再引用原先哨兵节点,无引用的哨兵节点将会被GC回收

image.png

9.小总结

你可能感兴趣的:(JUC-lock&AQS源码分析)