java面试题-什么是AQS?
深入理解AQS原理及应用
1. 什么是AQS?
AQS(AbstractQueuedSynchronizer)是Java中用于实现锁和同步器的抽象基类,位于java.util.concurrent.locks
包。它是除了Java自带的synchronized
关键字之外的锁机制,提供了一种强大而灵活的实现方式。
2. AQS的核心思想
AQS的核心思想是基于CLH队列实现的,其中CLH指的是Craig,Landin,和 Hagersten。它是一个虚拟的双向队列,不存在实际的队列实例,仅存在节点之间的关联关系。AQS通过维护一个volatile int state
和一个FIFO线程等待队列来实现锁的分配。
3. AQS的工作原理
AQS将每一条请求共享资源的线程封装成一个CLH锁队列的节点(Node)。当请求共享资源时,AQS会判断资源是否空闲,如果空闲则将当前请求资源的线程设置为有效的工作线程,并将共享资源设置为锁定状态。如果资源被占用,AQS会将线程加入等待队列,等待被唤醒。
AQS通过CAS(Compare And Swap)操作来改变状态标识,成功则获取锁成功,失败则进入等待队列,等待被唤醒。需要注意的是,AQS是自旋锁,在等待唤醒的时候,会使用自旋的方式不断尝试获取锁,直到成功或被其他线程获取成功。
4. AQS的具体实现方式
AQS维护了volatile int state
和一个FIFO线程等待队列。对于共享资源的访问,AQS定义了如下三种方法:
getState()
: 获取共享资源的状态。setState()
: 设置共享资源的状态。compareAndSetState()
: 使用CAS操作设置共享资源的状态。
AQS定义了两种资源共享方式:
- Exclusive(独占): 只有一个线程能执行,例如
ReentrantLock
。 - Share(共享): 多个线程可以同时执行,例如
Semaphore
、CountDownLatch
、ReadWriteLock
、CyclicBarrier
。
不同的自定义同步器争用共享资源的方式也不同。
5. 示例代码
下面通过一个简单的示例代码演示AQS的应用,我们以ReentrantLock
为例:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class AQSExample {
private static final Lock lock = new ReentrantLock();
public static void main(String[] args) {
// 使用ReentrantLock保护共享资源
new Thread(AQSExample::accessSharedResource).start();
new Thread(AQSExample::accessSharedResource).start();
}
private static void accessSharedResource() {
lock.lock(); // 获取锁
try {
// 访问共享资源
System.out.println(Thread.currentThread().getName() + " is accessing the shared resource.");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); // 释放锁
}
}
}
6. 总结及选择
AQS为Java提供了一种灵活而强大的实现锁和同步器的机制。通过深入理解AQS的原理和工作方式,我们能更好地选择和应用不同的同步机制来满足具体的应用需求。
- 本文标签: Java 面试题
- 本文链接: https://www.jietongc.com/article/59
- 版权声明: 本文由大熊科技原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权