队列同步器
概念
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修饰,而且getter
和seter
方法采用final进行修饰,目的是限制AQS的子类只能调用这两个方法对state的值进行设置和获取,而不能对其进行重写自定义设置/获取逻辑。
AQS中FIFO队列中节点的数据结构
当前线程获取同步状态失败时,同步器会将当前线程以及等待状态等信息构造成一个Node节点,并将其加入到同步队列,同时会阻塞当前线程。当同步状态释放时,同步器会把同步队列中的首节点中的线程唤醒,使其再次尝试获取同步状态。
参考内容
《Java并发编程的艺术》:Java中的锁
Last updated