队列同步器

概念

AbstractQueuedSynchronizer(AQS),是用来构建锁或者其他同步组件的基础框架,它使用了一个int成员变量(status)表示共享资源的同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。

  • status:多线程共享某资源时,该共享资源的状态(是否已经被其他线程锁住等),使用这个status来表示。

  • FIFO队列:当一些线程无法获取到共享资源,等待获取锁时,会放在一个容器中进行保存,这个容器就是FIFO队列。

在FIFO队列中,节点表示被阻塞的线程,队列节点元素有4种类型, 每种类型表示线程被阻塞的原因,这四种类型分别是:

  • CANCELLED: 表示该线程是因为超时或者中断原因而被放到队列中

  • CONDITION: 表示该线程是因为某个条件不满足而被放到队列中,需要等待一个条件,直到条件成立后才会出队

  • SIGNAL: 表示该线程需要被唤醒

  • PROPAGATE: 表示在共享模式下,当前节点执行释放release操作后,当前结点需要传播通知给后面所有节点

由于一个共享资源同一时间只能由一条线程持有,也可以被多个线程持有,因此AQS中存在以下两种模式:

  • 独占模式

    • 表示共享状态值state每次只能由一条线程持有,其他线程如果需要获取,则需要阻塞,如JUC中的ReentrantLock

  • 共享模式

    • 表示共享状态值state每次可以由多个线程持有,如JUC中的CountDownLatch

AQS中的共享状态值

AQS是基于一个共享的int类型的state值来实现同步器同步的:

多线程共享某资源时,该共享资源的状态(是否已经被其他线程锁住等),AQS使用status来表示。为了达到多线程同步的功能,必然对该值的修改必须多线程可见,因此,state采用volatile修饰,而且getterseter方法采用final进行修饰,目的是限制AQS的子类只能调用这两个方法对state的值进行设置和获取,而不能对其进行重写自定义设置/获取逻辑。

AQS中FIFO队列中节点的数据结构

当前线程获取同步状态失败时,同步器会将当前线程以及等待状态等信息构造成一个Node节点,并将其加入到同步队列,同时会阻塞当前线程。当同步状态释放时,同步器会把同步队列中的首节点中的线程唤醒,使其再次尝试获取同步状态。

参考内容

Java 并发编程 ----- AQS(抽象队列同步器)

队列同步器(AQS)详解

Java中的锁——队列同步器

《Java并发编程的艺术》:Java中的锁

Last updated