Java AQS锁实现原理
整体介绍
概念
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWctYmxvZy5jc2RuaW1nLmNuLzM4MDVkNzQ3NzcxOTQ3ZGJiYzRlMDhkOWJkNjBjMGJjLnBuZw==https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWcyMDIyLmNuYmxvZ3MuY29tL2Jsb2cvMjkxMDI1Mi8yMDIyMDgvMjkxMDI1Mi0yMDIyMDgxNDE0MTM0NzcwNC0xOTIwMDUyMS5naWY=
首先阅读一下类的源码注释,可以知道,这几个接口是最关键的。
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWctYmxvZy5jc2RuaW1nLmNuLzRiODkwM2EwNWUxZDQ3YzI5M2UwYWE0Y2I0NzdmYjlkLnBuZw==https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWcyMDIyLmNuYmxvZ3MuY29tL2Jsb2cvMjkxMDI1Mi8yMDIyMDgvMjkxMDI1Mi0yMDIyMDgxNDE0MTM0NzcwNC0xOTIwMDUyMS5naWY=
这几个方法是使用AQS类的关键,只有这几个方法是可以定制的,其他方法几乎都是final的,不可修改。
从代码实现上看,能看到的变量几乎都是volatile的,能看到的方法几乎都是CAS或者Unsafe类的原子方法。
接下来我们来整理一下这个类的字段和方法,这里我们主要关注private字段和public方法。
字段
volatile int state:同步状态。
volatile Node head:等待队列的头,延迟初始化。
volatile Node tail:等待队列的尾部。初始化后,仅通过casTail修改。
方法
获取锁:
acquire(int arg)
acquireShared(int arg)
释放锁:
release(int arg)
releaseShared(int arg)
等待队列:
hasQueuedThreads()
getFirstQueuedThread()
isQueued(Thread thread)
getQueuedThreads()
getExclusiveQueuedThreads()
getSharedQueuedThreads()
条件对象ConditionObject:
await()
signal()
架构
AQS整体结构,包括加锁/释放锁,条件对象await/signal。
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWctYmxvZy5jc2RuaW1nLmNuLzQyYzU1ZjA0NGJmZjQwY2FiNDcwMGE5Y2JhNjkxOWJkLnBuZw==https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWcyMDIyLmNuYmxvZ3MuY29tL2Jsb2cvMjkxMDI1Mi8yMDIyMDgvMjkxMDI1Mi0yMDIyMDgxNDE0MTM0NzcwNC0xOTIwMDUyMS5naWY=
功能说明
锁
数据结构
锁的数据结构
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWctYmxvZy5jc2RuaW1nLmNuLzk1ZjZlOGM0Mjg0MzQ4OGViYjYzNzRmYjUwNzBkM2UyLnBuZw==https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWcyMDIyLmNuYmxvZ3MuY29tL2Jsb2cvMjkxMDI1Mi8yMDIyMDgvMjkxMDI1Mi0yMDIyMDgxNDE0MTM0NzcwNC0xOTIwMDUyMS5naWY=
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWctYmxvZy5jc2RuaW1nLmNuLzM1NDdiNjE2NzEzMzRhZTg4N2M4OWNiZjNlMjBkZGU1LnBuZw==https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWcyMDIyLmNuYmxvZ3MuY29tL2Jsb2cvMjkxMDI1Mi8yMDIyMDgvMjkxMDI1Mi0yMDIyMDgxNDE0MTM0NzcwNC0xOTIwMDUyMS5naWY=
一个状态字段state表示同步状态,0表示没有锁竞争,1表示有锁竞争。
head跟tail分别是等待队列的头节点和尾节点,该等待队列是用双向链表实现的。
节点的数据结构
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWctYmxvZy5jc2RuaW1nLmNuLzMyYTRjZjFmZmY1NDRkMWU5M2JhZTQ0ZTNmNjE1MWQwLnBuZw==
prev:前驱节点
next:后继节点
waiter:等待锁的线程
status:节点状态
节点https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWctYmxvZy5jc2RuaW1nLmNuLzU2ZGE3NjRmYThkZjQ0Yjg5MTRkMDU2Y2JiMTIwMGNlLnBuZw==https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWcyMDIyLmNuYmxvZ3MuY29tL2Jsb2cvMjkxMDI1Mi8yMDIyMDgvMjkxMDI1Mi0yMDIyMDgxNDE0MTM0NzcwNC0xOTIwMDUyMS5naWY=
节点状态其实有4种:
取消状态:status1,独占锁并发数=1。
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWctYmxvZy5jc2RuaW1nLmNuL2QzMjcxMzJmODQwNzRmMzNhZTZiMzllMjAwNmUyY2ZlLnBuZw==https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWcyMDIyLmNuYmxvZ3MuY29tL2Jsb2cvMjkxMDI1Mi8yMDIyMDgvMjkxMDI1Mi0yMDIyMDgxNDE0MTM0NzcwNC0xOTIwMDUyMS5naWY=
共享锁实现过程
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWctYmxvZy5jc2RuaW1nLmNuL2QzMDJiNzJjYTI0YjQzZjRhZThlYTczNzIxMjJkMmJkLnBuZw==https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWcyMDIyLmNuYmxvZ3MuY29tL2Jsb2cvMjkxMDI1Mi8yMDIyMDgvMjkxMDI1Mi0yMDIyMDgxNDE0MTM0NzcwNC0xOTIwMDUyMS5naWY=
1.tryAcquireShared
这是一个protected方法,在Semaphore里实现了FairSync和NonfairSync,也就是公平锁和非公平锁。
1-1.FairSync in Semaphore
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWctYmxvZy5jc2RuaW1nLmNuLzM2MGQwY2VkYmJmYzQ4MGZiYjk0NzcyOWQyZDJkMjlmLnBuZw==https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWcyMDIyLmNuYmxvZ3MuY29tL2Jsb2cvMjkxMDI1Mi8yMDIyMDgvMjkxMDI1Mi0yMDIyMDgxNDE0MTM0NzcwNC0xOTIwMDUyMS5naWY=
如果有前驱节点在等待,返回失败;
如果剩余的并发数
页:
[1]