AbstratQuenedSynchronizer抽象队列同步器
一. 简单理解
源码讲解视频
博客
核心参数
- 变量state :没加锁state=0,加锁state=1
- 加锁线程:CAS 设置state=1
加锁过程
- 尝试state的值由0变为1,如果发现state的值已经不为0了而是1,说明有线程加锁了
- 如果加锁失败,则放入等待队列中,等待其他线程释放锁
释放锁过程
- 将state递减为0,如果是可重入锁,例state=2,则需递减到0才会释放锁
- 将加锁线程set为null
可重入锁
判断加锁线程是否是当前线程(记录线程id)
ReentrantLcok、Synchronized
可以多次加锁lock和释放锁unlock
二. 源码剖析
源码讲解
1.核心参数
-
int state
ReentrantLcok、ReentrantReanWriteLock获取锁的方式是通过修改state变量
CountDownLanch的计时器和Semaphore的信号量也是使用的state -
双向链表 (未获取锁的线程)
如果ReentrantLcok没拿到锁资源,则会将线程封装成Node存入,Node保存当前线程
为什么这里使用双向链表?
如果准备获取锁资源,需要出队,双向链表能够更好的修改头尾节点的指向
双向链表初始化thread=null的节点,如果有新Node加入,(1)则优先修改Node自身的指向,指向为上一个节点(先操作私有变量,再操作共享变量volatile,保住原子性),(2 )让尾节点tail指向当前Node(3)让上一节点指向当前节点(存在多节点竞争,需要CAS加锁操作)
走321,需要在多加一次锁
-
单向链表(存wait挂起线程)
waitSet
存储ReentrantLcok使用await挂起的线程
存储Synchronized 使用wait挂起的线程
exq、EntryLis
存储没获取锁资源的线程
2.ReentrantLock
abstract抽象类Sync继承了AQS
(1)ReentrantLock构造器
ReentrantLock默认无参构造非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
有参构造,入参true公平锁new FairSync(),false非公平锁new NonFairSync()
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
(2)lock()
抽象类Syns有两个实现类NonfairSync和FairSync,所以ReentrantLock有非公平锁和公平锁两种实现,所以lock()方法也有两种
- 非公平锁NonfairSync的lock()
直接使用CAS,尝试将state由0改为1(CAS:同一时间多个线程执行,只有一个能成功),如果失败则走acquire(1)
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
- 公平锁FairSync的lock()
acquire(1)
final void lock() {
acquire(1);
}
(3)acquire()方法 拿锁
acquire直接使用的AQS的方法,不区分公平锁、非公平锁实现
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
- tryAcquire 再次拿锁,有公平锁、非公平锁两种实现
- addWaiter 没拿到锁,等待
- acquireQueued 挂起线程和后续被换线获取锁资源
acquire()的非公平锁实现nonfairTryAcquire(),尝试插队获取锁,tryLock()也使用的该方法
final boolean nonfairTryAcquire(int acquires) {
//获取当前线程对象
final Thread current = Thread.currentThread();
//获取state
int c = getState();
//如果锁没用被有其他线程获取,则可以尝试获取
if (c == 0) {
//非公平锁直接CAS尝试将state从0改为1
if (compareAndSetState(0, acquires)) {
//成功拿到锁,并将当前线程设置为加锁线程
setExclusiveOwnerThread(current);
return true;
}
}
//如果state!=1,判断当前线程是否为加锁线程
else if (current == getExclusiveOwnerThread()) {
//如果是加锁线程,则锁重入,state+1
int nextc = c + acquires;
//防止int类型溢出,一般不会出现,可能先内存溢出
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
非阻塞锁tryLock()复用该方法nonfairTryAcquire()
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
acquire()的公平锁实现tryAcquire(),排队获取锁
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//判断是否有其他线程在等待,如果没用则获取锁,如果需要排队则放弃
//如果当前线程排在第一位则抢锁(因为被唤醒线程也会执行tryAcquire方法,这里是为了考虑此情况)
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
(4)addWaiter(Node.EXCLUSIVE), arg)
将未获取到锁的线程,封装为Node,添加到双向链表
3.CAS unsafe.compareAndSwapInt
tryAcquire()方法中compareAndSetState()方法
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
底层是native修饰的Unsafe工具类的compareAndSwapInt(),使用CAS指令修改(硬件层面支持)
- this:当前对象
- stateOffset:获取state内存偏移量
- expect:state的值
- update:需要修改的state的值,update=1
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
获取当前AQS类下state属性在内存中的偏移量,也就是获取state属性的地址,因为地址是长整形所以用long接收
static final long stateOffset= unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("state"));