深入浅出分析 AQS 中 acquire() 和 release() 方法的奥秘
2024-02-22 09:07:32
1. AQS 简介
AQS(AbstractQueuedSynchronizer)是 Java 并发编程中非常重要的一个类,它提供了一套用于构建锁和同步器的数据结构和算法。AQS 的设计思想非常巧妙,它使用了一个队列来管理线程的等待和唤醒,从而实现了公平锁和非公平锁的实现。
2. AQS 的状态
AQS 内部维护了一个名为 state 的整型变量,该变量记录了 AQS 的当前状态。state 的值可以是以下几个常量:
- 0:表示 AQS 没有被任何线程持有,即未上锁。
- 1:表示 AQS 被一个线程持有,即已上锁。
- 2:表示 AQS 处于独占模式,即只有一个线程可以持有 AQS。
- 4:表示 AQS 处于共享模式,即多个线程可以同时持有 AQS。
3. acquire() 方法
acquire() 方法是 AQS 中用于获取锁的方法。当一个线程想要获取锁时,它会调用 acquire() 方法。acquire() 方法首先会尝试使用 CAS(Compare-And-Swap)操作将 state 的值从 0 改为 1。如果成功,则表示该线程获得了锁。如果失败,则表示 AQS 已经被其他线程持有,该线程需要进入等待队列等待锁的释放。
4. release() 方法
release() 方法是 AQS 中用于释放锁的方法。当一个线程持有锁时,它可以调用 release() 方法来释放锁。release() 方法会将 state 的值从 1 改为 0,并唤醒等待队列中等待锁的线程。
5. 源码分析
下面我们来对 acquire() 和 release() 方法的源码进行分析。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus == Node.SIGNAL)
unparkSuccessor(h);
return true;
}
return false;
}
在 acquire() 方法中,首先会调用 tryAcquire() 方法尝试获取锁。如果成功,则直接返回。如果失败,则会调用 acquireQueued() 方法将当前线程加入等待队列,并等待锁的释放。
在 release() 方法中,首先会调用 tryRelease() 方法尝试释放锁。如果成功,则会唤醒等待队列中等待锁的线程。如果失败,则表示 AQS 已经被其他线程持有,该线程无法释放锁。
6. 总结
通过对 acquire() 和 release() 方法的源码分析,我们对 AQS 的工作原理有了更深入的了解。AQS 的设计思想非常巧妙,它使用了一个队列来管理线程的等待和唤醒,从而实现了公平锁和非公平锁的实现。