AQS介绍
AQS(AbstractQueuedSynchronizer)是 Java 并发包(java.util.concurrent)中一个重要的基础类,用于实现同步器(Synchronizer)的框架。AQS 提供了一种基于 FIFO 等待队列的机制,使得开发者可以相对容易地实现各种自定义的同步组件,例如锁、信号量、倒计时门栓等。
AQS 主要是一个抽象类,它定义了一些基本的同步操作,而具体的同步逻辑需要子类继承并实现。AQS 内部维护了一个等待队列,用于管理等待获取同步状态的线程。
AQS 的核心思想是,通过维护一个 state 变量来表示同步状态,当 state 为 0 时表示没有线程占用资源,当 state 大于 0 时表示资源已经被占用。具体的同步操作如锁的获取(acquire)和释放(release)等都是基于这个 state 变量来实现的。
AQS 提供了两种模式来实现同步组件:独占模式(Exclusive mode)和共享模式(Shared mode)。
在独占模式下,只有一个线程可以获取同步状态,比如可重入锁(ReentrantLock);
在共享模式下,多个线程可以同时获取同步状态,比如读写锁(ReentrantReadWriteLock)。
AQS的常用方法
- getState():获取当前同步状态。
- setState(int newState):设置当前同步状态。
- compareAndSetState(int expect,int update):使用CAS设置当前状态,该方法能够保证状态
设置的原子性。
继承AQS需要实现的方法
-
tryAcquire(int arg):尝试获取同步状态,成功返回 true,否则返回 false。
-
tryRelease(int arg):尝试释放同步状态。
-
tryAcquireShared(int arg):尝试以共享模式获取同步状态,成功返回一个大于 0 的值,表示可用资源数量,失败返回小于 0 的值。
-
tryReleaseShared(int arg):尝试以共享模式释放同步状态。
通过继承AQS来实现自定义锁
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
public class CustomLock {
private final Sync sync = new Sync();
public void lock() {
sync.acquire(1);
}
public void unlock() {
sync.release(1);
}
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 IllegalMonitorStateException("Lock not held");
}
setExclusiveOwnerThread(null);
setState(0);
return true;
}
@Override
protected boolean isHeldExclusively() {
return getState() == 1;
}
}
public static void main(String[] args) {
CustomLock customLock = new CustomLock();
Runnable task = () -> {
customLock.lock();
try {
System.out.println(Thread.currentThread().getName() + " has acquired the lock.");
Thread.sleep(1000); // Simulating some work
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
customLock.unlock();
System.out.println(Thread.currentThread().getName() + " has released the lock.");
}
};
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
}
}