Java AQS 是什么
一文搞懂AQS
AQS详解
什么是AQS
AQS(AbstractQueuedSynchronizer)是一个用于构建锁和同步器的框架。它通过一个先进先出的等待队列管理多个线程的同步操作。AQS 提供了资源状态管理、线程排队管理和模板方法等核心功能。
核心思想
AQS 的核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制。AQS 使用 CLH 队列锁实现这一机制,将每条请求共享资源的线程封装成一个 CLH 锁队列的一个结点(Node)来实现锁的分配。
主要功能
- 资源状态管理:AQS 使用一个 volatile 类型的整数变量(state)来表示同步状态。子类可以定义该状态的具体意义,例如对于独占锁,state 表示锁的持有状态(0 表示未持有,1 表示持有)。
- 线程排队管理:AQS 使用一个 FIFO 等待队列来管理处于等待状态的线程。当线程请求无法获取同步状态时,会被加入等待队列。
- 模板方法:AQS 提供了一系列模板方法,子类可以通过实现这些方法来定义具体的同步机制。
应用示例
ReentrantLock
ReentrantLock 是一种基于 AQS 实现的可重入独占锁。它有两种模式:公平模式和非公平模式。
public class AQSDemo {
private static int num;
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
new Thread(() -> {
lock.lock();
try {
Thread.sleep(1000);
num += 1000;
System.out.println("A 线程执行了1秒, num = " + num);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "A").start();
new Thread(() -> {
lock.lock();
try {
Thread.sleep(500);
num += 500;
System.out.println("B 线程执行了0.5秒, num = " + num);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "B").start();
new Thread(() -> {
lock.lock();
try {
Thread.sleep(100);
num += 100;
System.out.println("C 线程执行了0.1秒, num = " + num);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "C").start();
}
}
CountDownLatch
CountDownLatch 是一种基于 AQS 实现的同步工具,它允许一个或多个线程等待一组操作完成。
public class CountDownLatchExample {
private static final int THREAD_COUNT = 550;
public static void main(String[] args) throws InterruptedException {
ExecutorService threadPool = Executors.newFixedThreadPool(300);
final CountDownLatch countDownLatch = new CountDownLatch(THREAD_COUNT);
for (int i = 0; i < THREAD_COUNT; i++) {
final int threadNum = i;
threadPool.execute(() -> {
try {
test(threadNum);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}
});
}
countDownLatch.await();
threadPool.shutdown();
System.out.println("finish");
}
public static void test(int threadnum) throws InterruptedException {
Thread.sleep(1000);
System.out.println("threadNum:" + threadnum);
Thread.sleep(1000);
}
}
通过这些示例,可以看到 AQS 在 Java 并发编程中的重要性和广泛应用。