Java AQS(AbstractQueuedSynchronizer)面经
简介
Java AQS(AbstractQueuedSynchronizer)是Java并发包中一个重要的基础类,用于实现锁和同步器的底层工具。AQS提供了一种用于构建锁和同步器的框架,可以方便地实现各种并发控制的机制。
AQS的基本原理
AQS的基本原理是通过一个FIFO(先进先出)的双向队列来管理线程的等待状态,并利用CAS(CompareAndSet)操作来实现原子性的状态更新。AQS维护了一个int类型的状态变量,通过状态的不同值来表示不同的线程状态。
AQS的主要方法包括:
acquire
:获取锁/同步器的操作,如果获取失败则进入等待队列。release
:释放锁/同步器的操作,同时唤醒等待队列中的第一个线程。tryAcquire
:尝试获取锁/同步器的操作,如果获取成功则返回true,否则返回false。tryRelease
:尝试释放锁/同步器的操作,如果释放成功则返回true,否则返回false。
AQS的应用场景
AQS提供了一种灵活的框架,可以用于实现各种并发控制的机制。常见的应用场景包括:
- 独占锁:通过实现
tryAcquire
和tryRelease
方法来实现独占锁的机制。 - 共享锁:通过实现
tryAcquireShared
和tryReleaseShared
方法来实现共享锁的机制。 - 同步器:通过实现
tryAcquire
和tryRelease
方法来实现一个自定义的同步器。
下面以一个简单的示例来演示AQS的应用场景。
示例:旅行图
我们以一个旅行图的例子来说明AQS的使用。假设有三个线程(A、B、C)要参加一次旅行,他们需要依次获取出行的权限。
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
public class TravelPermission {
private static class Sync extends AbstractQueuedSynchronizer {
@Override
protected boolean tryAcquire(int arg) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
@Override
protected boolean tryRelease(int arg) {
if (getState() == 0) {
throw new IllegalStateException("未获取到出行权限");
}
setExclusiveOwnerThread(null);
setState(0);
return true;
}
@Override
protected boolean isHeldExclusively() {
return getState() == 1;
}
}
private final Sync sync = new Sync();
public void acquire() {
sync.acquire(1);
}
public void release() {
sync.release(1);
}
}
上面的代码定义了一个TravelPermission
类,它使用AQS实现了一个出行权限的控制机制。每个线程在出行前需要先获取出行权限,出行后需要释放出行权限。
```sequenceDiagram
A->>TravelPermission: acquire()
TravelPermission->>A: tryAcquire()
alt acquire成功
A-->>TravelPermission: setExclusiveOwnerThread()
TravelPermission-->>A: true
else acquire失败
A-->>TravelPermission: false
end
A->>TravelPermission: release()
TravelPermission->>A: tryRelease()
alt release成功
TravelPermission-->>A: true
else release失败
TravelPermission-->>A: IllegalStateException
end
```markdown
```mermaid
journey
A[线程A] --> B[线程B] --> C[线程C]
上面的示例代码中,tryAcquire
方法尝试获取出行权限,如果成功则返回true,否则返回false。tryRelease
方法用于释放出行权限。
在使用这个出行权限控制机制时,线程A、B、C依次调用acquire
方法获取出行权限,并在出行结束后调用release
方法释放出行权限。
public class Main {
public static void main(String[] args) {
TravelPermission travelPermission = new TravelPermission();