原创

java面试题-什么是AQS?

深入理解AQS原理及应用

1. 什么是AQS?

AQS(AbstractQueuedSynchronizer)是Java中用于实现锁和同步器的抽象基类,位于java.util.concurrent.locks包。它是除了Java自带的synchronized关键字之外的锁机制,提供了一种强大而灵活的实现方式。
file

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定义了两种资源共享方式:

  1. Exclusive(独占): 只有一个线程能执行,例如ReentrantLock
  2. Share(共享): 多个线程可以同时执行,例如SemaphoreCountDownLatchReadWriteLockCyclicBarrier

不同的自定义同步器争用共享资源的方式也不同。

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的原理和工作方式,我们能更好地选择和应用不同的同步机制来满足具体的应用需求。

正文到此结束
本文目录