Java并发编程框架AQS

525 阅读3分钟

这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战

前言

AbstractQueuedSynchronizer 抽象的队列式的同步器,AQS 定义了一套多线程访问共享资源的同步器框架. JUC中的大部分同步类都是依据AQS实现的.

1. AQS原理

AQS 是一个抽象类,主要通过继承的方式使用,本身没有实现任何接口,仅仅定义了同步状态获取和释放的方法.

AbstractQueuedSynchronizer.png

主要原理:

image.png AQS核心思想是,如果被请求的共享资源空闲,那么就将当前请求资源的线程设置为有效的工作线程,将共享资源设置为锁定状态;如果共享资源被占用,就需要一定的阻塞等待唤醒机制来保证锁分配。

image.png CLH:Craig、Landin and Hagersten队列,是单向链表,AQS中的队列是CLH变体的虚拟双向队列(FIFO),AQS是通过将每条请求共享资源的线程封装成一个节点来实现锁的分配。

1.1 AbstractOwnableSynchronizer

这个类比较简单设置和获取独占锁的拥有者线程

1.2 AbstractQueuedSynchronizer

1.2.1 主要的数据结构

先看下成员变量,主要是这3个成员变量, Node head, tail 和state

image.png

还有一些offset, stateOffset表示state这个字段在AQS类的内存中相对于该类首地址的偏移量.

解释: 一个Java对象可以看成是一段内存,每个字段都得按照一定的顺序放在这段内存里,通过这个方法可以准确地告诉你某个字段相对于对象的起始内存地址的字节偏移。用于在后面的compareAndSwapInt中,去根据偏移量找到对象在内存中的具体位置.

Node 节点成员变量和方法,每个字段和方法的解释美团的AQS原理文章写的非常好,我这边就直接截图了.

image.png

image.png

image.png

1.2.2 同步状态State

AQS中维护了一个名为state的字段,意为同步状态,是由Volatile修饰的,用于展示当前临界资源的获锁情况。
我们可以通过修改State字段表示的同步状态来实现多线程的独占模式和共享模式(加锁过程)。

Exclusive-独占,只有一个线程能执行,如ReentrantLock 
Share-共享,多个线程可以同时执行,如Semaphore/CountDownLatch

1.2.3 AQS中重要的方法

image.png 以ReentrantLock源码为例,我们看下代码的实现

public class ReentrantLockDemo {
    private ReentrantLock reentrantLock = new ReentrantLock();
    public void demo() {
        reentrantLock.lock();;
        try {
            // 业务逻辑
        } catch (Exception e) {

        } finally {
            reentrantLock.unlock();
        }
    }
}

Sync继承AQS, 大概的流程如下

image.png

总结:

AQS 定义了一套多线程访问共享资源的同步器框架. 很多同步器是根据不同的业务场景基于AQS实现的不同的同步策略,比如ReentrantLock 公平锁,非公平, 独占模式,可重入等, 在比如共享模式的Semaphore和CountDownLatch等。

参考

stateOffset
从ReentrantLock的实现看AQS的原理及应用