1 AQS定义:
AQS是Java并发包java.util.concurrent.locks中一个核心并发框架,用于构建锁和同步器,
如:
- ReentrantLock
- ReentrantReadWriteLock
- CountDownLatch
- Semaphore
- FutureTask

2 AQS核心元素
2.1 state
volatile修饰整型关键字state,用来标识资源的占用状态(如是否被锁定),类似信号灯指挥线程的行动。
以ReentrantLock为例:state=0表示锁空闲,线程可以去竞争锁;state=1 表示有线程已经获取该锁,其他线程不可再获取整个锁,如果是同一线程再次获取,state会累加。只有state降为0后锁才会释放,其他线程才有机会获得锁
以CountDownLatch为例:state充当计数器,初始值设置为正数,比如设置为5,每个线程调用countDown()方法,state就会减1,等到state=0,那些因为调用await()方法而阻塞的线程就会被唤醒,尝试获取锁
state提供方法:
① getState() 线程安全查看state当前值
②setState() 线程安全给state设置新值,靠volatile保证线程安全
③compareAndSetState()使用CAS操作更新state,只有预期值和当前位置值一样才会修改,保证原子性,底层靠Usafe类调用CPU指令来实现该操作
2.2 FIFO队列
FIFO队列是一个双向链表结构,由一个个Node节点串联。当线程尝试获取资源tryAquire()失败后就会被封装成Node节点,通过addWaiter()方法加入队列尾巴。一旦进入队列,线程进入等待状态就等待被唤醒
FIFO队列关键属性:
head:同步队列的头节点,头节点指向真正持有锁资源的节点,后续节点只有等待head节点释放资源来唤醒自己
tail: 尾节点,最新来的进程会置为尾节点
node:作为同步队列和条件队列里的节点,它内部属性丰富得很。除了前面提到的 waitStatus、prev、next 和 thread,还有 nextWaiter,这是在条件队列里用的,指向节点的下一个等待者
head -> Node1 -> Node2 -> ... -> tail

2.3获取/释放方法
核心方法:
// 共享模式 protected int tryAcquireShared(int arg); protected boolean tryReleaseShared(int arg); // 独占模式 protected boolean tryAcquire(int arg); protected boolean tryRelease(int arg);
获取锁流程:调用tryAcquire()方法,如果返回true线程获取到锁,如果返回false说明资源被占,线程被封装成Node节点,通过addWaiter()方法加入队列尾巴,接着在acquireQueued方法陷入自旋,在队列中自旋检查前驱节点是否为头节点并尝试获取资源,如果获取成功,将自己设为头节点
释放锁流程:调用tryRelease()方法,如果释放成功,唤醒后继节点中的线程
2.3.1 tryAcquire()--Reentrant Lock为例--独占模式(ReentrantLock分为公平锁和非公平锁):
ReentrantLock的tryAcquire()实现如下:
非公平锁:线程一开始不管队列里有没有前节点,先执行CAS操作,如果state=0,就会抢占锁,然后把state置为1,顺便把当前线程标记成独占锁;如果state=1判断是否是不是自己已经拿到的锁,如果是state++体现可重入特性。如果失败则入队挂起
公平锁:线程先判断是否有前节点,如果没有才会去抢锁,如果有则继续排队挂起线程,只有被前驱节点唤醒后再次尝试获取锁
非公平tryAcquire实现代码
protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { // 尝试直接 CAS 获取锁 if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { // 可重入,加重入次数 int nextc = c + acquires; setState(nextc); return true; } return false; }
公平锁tryAcquire实现代码:
protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && // 关键点:检查是否有等待更久的线程 compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } // ...重入逻辑 return false; } public final boolean hasQueuedPredecessors() { Node t = tail; Node h = head; Node s; return h != t && // 队列不为空 ((s = h.next) == null || s.thread != Thread.currentThread()); }
2.3.2 tryRelease
只有state=0才会调用释放锁
protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
AQS 线程状态控制核心机制:LockSupport
AQS 底层通过 LockSupport.park() 和 unpark(thread) 来挂起/唤醒线程:
park():当前线程阻塞,等待被唤醒;
unpark(Thread t):唤醒指定线程;
这种控制机制替代了传统的 wait/notify,更灵活、底层、性能好
参考:https://juejin.cn/post/7454026458250166272
浙公网安备 33010602011771号