分为独占锁和共享锁:
获取独占锁:
image.png final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
CAS设置为1,成功则获取锁,否则调用 acquire获取锁
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
tryAcquire 作用也是做CAS获取锁,如果已经是同一线程重入,state+1(释放时会减1),如果ryAcquire成功就结束,如果没有成功,则通过addWaiter将当前线程包装成一个Node节点,通过CAS原子操作,加入队列的尾部.
acquireQueued() 中会判断这个node节点的前一个节点是不是head节点(也就是持有锁的节点),如果是,那就调用tryAcquire再次通过CAS自旋去尝试获取锁,如果获取锁失败后,进入挂起逻辑。
总结:
在独占锁模式下,用 state 值表示锁并且 0 表示无锁状态,0 -> 1 表示从无锁到有锁,仅允许一条线程持有锁,其余的线程会被包装成一个 Node 节点放到队列中进行挂起,队列中的头节点表示当前正在执行的线程,当头节点释放后会唤醒后继节点,从而印证了 AQS 的队列是一个 FIFO 同步队列。
获取共享锁:
共享功能:只要头节点获取锁成功,就在唤醒自身节点对应的线程的同时,继续唤醒AQS队列中的下一个节点的线程,
每个节点在唤醒自身的同时还会唤醒下一个节点对应的线程,以实现共享状态的“向后传播”,从而实现共享功能。
refer:https://www.jianshu.com/p/76949bca657a
http://objcoding.com/2019/05/05/aqs-exclusive-lock/
网友评论