AbstractQueuedSynchronizer
总结
1、Java并发包的抽象类
2、简化自定义同步器的实现,为自定义的同步组件提供了一个基础框架
3、核心概念:
同步状态state:一个volatile的int成员变量,用于表示同步状态(自定义同步器共享的状态)
同步队列:维护了一个双向链表的FIFO的队列,用于存放等待获取同步状态的线程;
独享vs共享模式:
支持两种不同的获取同步状态的方式:独占模式和共享模式。独占模式意味着一次只有一个线程可以获得同步状态;共享模式允许多个线程同时获得同步状态;
4、关键类和方法
- Node:AQS 的内部类,表示同步队列中的一个节点,每个节点代表一个等待的线程。
- ConditionObject:AQS 的内部类,实现条件变量的功能,允许等待线程在满足特定条件时被唤醒。
- getState(), setState(int), compareAndSetState(int, int):这些方法用于操作同步状态
state
。 - tryAcquire(int):尝试获取独占模式下的同步状态。
- tryRelease(int):尝试释放独占模式下的同步状态。
- tryAcquireShared(int):尝试获取共享模式下的同步状态。
- tryReleaseShared(int):尝试释放共享模式下的同步状态。
- isHeldExclusively():检查当前线程是否独占了同步状态
5、模版方法
AQS 提供了一系列模板方法,子类需要根据具体的同步需求来实现这些方法。这些方法包括但不限于:
- protected final void acquire(int arg):独占模式下获取同步状态。
- protected final boolean release(int arg):独占模式下释放同步状态。
- protected final int acquireShared(int arg):共享模式下获取同步状态。
- protected final boolean releaseShared(int arg):共享模式下释放同步状态。
概述
Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues.
一个 依赖 FIFO队列 实现 阻塞Lock和同步器 的框架;
This class is designed to be a useful basis for most kinds of synchronizers that rely on a single atomic {@code int} value to represent state.
被设计 对于 依赖原子int值 展示state 的同步器 是很有用的;
Subclasses must define the protected methods that change this state, and which define what that state means in terms of this object being acquired or released.
子类 必须定义该类的改变state的protected方法 (state表示获取、释放某个对象的state)
Subclasses can maintain other state fields, but only the atomically updated {@code int} value manipulated using methods {@link #getState}, {@link #setState} and {@link #compareAndSetState} is tracked with respect to synchronization.
子类只能使用getState、setState、compareAndSetState
Subclasses should be defined as non-public internal helper classes that are used to implement the synchronization properties of their enclosing class.
Class {@code AbstractQueuedSynchronizer} does not implement any synchronization interface. Instead it defines methods such as {@link #acquireInterruptibly} that can be invoked as appropriate by concrete locks and related synchronizers to implement their public methods.
AbstractQueuedSynchronizer没有实现任何同步接口;
相反 提供了acquireInterruptibly方法 被合适的Lock调用;
This class supports either or both a default <em>exclusive</em> mode and a <em>shared</em> mode. 支持 共享、排他模式;
When acquired in exclusive mode, attempted acquires by other threads cannot succeed. 排他模式,其他线程获取将失败;
Shared mode acquires by multiple threads may (but need not) succeed. 共享模式,多线程获取成功;
Threads waiting in the different modes share the same FIFO queue. 不同模式下等待的线程 共享一个FIFO队列;
Usually, implementation subclasses support only one of these modes, but both can come into play for example in a {@link ReadWriteLock}.
通常,子类只支持一种模式,但如在ReadWriteLock中,2种模式都生效;
This class defines a nested {@link ConditionObject} class that can be used as a {@link Condition} implementation by subclasses supporting exclusive mode for which method {@link #isHeldExclusively} reports whether synchronization is exclusively held with respect to the current thread, method {@link #release} invoked with the current {@link #getState} value fully releases this object, and {@link #acquire}, given this saved state value, eventually restores this object to its previous acquired state.
定义了一个内部类ConditionObject
No {@code AbstractQueuedSynchronizer} method otherwise creates such a condition, so if this constraint cannot be met, do not use it.
The behavior of {@link ConditionObject} depends of course on the semantics of its synchronizer implementation.
This class provides inspection, instrumentation, and monitoring methods for the internal queue, as well as similar methods for condition objects.
为内部队列 提供了检测、监控方法,也为ConditionObject提供了类似的方法;
These can be exported as desired into classes using an {@code AbstractQueuedSynchronizer} for their synchronization mechanics.
可以根据需要使用AbstractQueuedSynchronizer实现同步机制;
Serialization of this class stores only the underlying atomic integer maintaining state, so deserialized objects have empty thread queues.
该类的序列化仅存储integer的state值,所以反序列化队列是空的;
Typical subclasses requiring serializability will define a {@code readObject} method that restores this to a known initial state upon deserialization.
子类需要定义一个readObject方法,反序列化将其恢复到初始状态;
链路
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements Serializable { /** * Wait queue node class. 等待队列节点 * The wait queue is a variant of a "CLH" (Craig, Landin, and Hagersten) lock queue. * 等待队列是一个CLH锁队列变体 * CLH locks are normally used for spinlocks. * CLH锁 通常被用来自旋锁 * * +------+ prev +-----+ +-----+ * head | | <---- | | <---- | | tail * +------+ +-----+ +-----+ * * To enqueue into a CLH lock, you atomically splice it in as new tail. * 加入lock队列,需要 拼接一下tail * To dequeue, you just set the head field. * 离队,仅需要修改head */ static final class Node { static final Node EXCLUSIVE = null; volatile Node next; volatile Node prev; volatile Thread thread; // The thread that enqueued this node. Node nextWaiter; Node(Node mode) { // Used by addWaiter this.nextWaiter = mode; this.thread = thread; } } /** * The synchronization state. */ private volatile int state; private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long stateOffset; /** * Acquires in exclusive mode, ignoring interrupts. * 以互斥模式获取lock * Implemented by invoking at least once {@link #tryAcquire}, returning on success. * 调用tryAcquire,返回成功 * Otherwise the thread is queued, possibly repeatedly blocking and unblocking, invoking {@link #tryAcquire} until success. * 否则线程将被排队 * * @param arg */ public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } /** * tryAcquire,由子类实现 */ protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException(); } /** * Creates and enqueues node for current thread and given mode. * 当前线程 以给定模式创建&排队 */ private Node addWaiter(Node mode) { } /** * Acquires in exclusive uninterruptible mode for thread already in queue. * 以互斥模式获取队列中的线程 * Used by condition wait methods as well as acquire. * @param node * @param arg * @return */ final boolean acquireQueued(final Node node, int arg) { } /** * interrupt current thread. * 中断当前线程 */ static void selfInterrupt() { Thread.currentThread().interrupt(); } /** * Returns the current value of synchronization state. */ protected final int getState() { return state; } /** * Queries whether any threads have been waiting to acquire longer than the current thread. * 查询是否有比当前线程等待获取lock时间更长的线程 */ public final boolean hasQueuedPredecessors() { // The correctness of this depends on head being initialized // before tail and on head.next being accurate if the current // thread is first in queue. Node t = tail; // Read fields in reverse initialization order Node h = head; Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); } /** * Atomically sets synchronization state to the given updated value if the current state value equals the expected value. * 如果当前值和预期的相等,就更新 */ protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update); } /** * 释放lock */ public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; } /** * Wakes up node's successor, if one exists. * 唤醒该节点的接替者 */ private void unparkSuccessor(Node node) { /* * If status is negative (i.e., possibly needing signal) try * to clear in anticipation of signalling. It is OK if this * fails or if status is changed by waiting thread. */ int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0); /* * Thread to unpark is held in successor, which is normally * just the next node. But if cancelled or apparently null, * traverse backwards from tail to find the actual * non-cancelled successor. */ Node s = node.next; if (s == null || s.waitStatus > 0) { s = null; for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } if (s != null) LockSupport.unpark(s.thread); } }
核心思想
如果被请求的共享资源空闲,则将 当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。
如果被请求的共享资源被占用,那么就需要一套 线程阻塞等待以及被唤醒时锁分配 的机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中;
实现思路
使用一个volatile的int成员变量来表示同步状态,使用CAS对该同步状态进行原子操作实现对其值的修改;
(
状态信息通过procted类型的getState,setState,compareAndSetState进行操作;
)
通过内置的FIFO队列来完成获取资源线程的排队工作;
(
将 每条请求共享资源的线程 封装成 一个CLH锁队列的一个结点(Node) 来实现锁的分配;
CLH(Craig,Landin,and Hagersten)队列是 一个虚拟的双向队列 (虚拟的双向队列即 不存在队列实例,仅存在结点之间的关联关系)
)
对共享资源的共享方式
Exclusive(独占):
同一时间只能有一个线程能执行;
如ReentrantLock。又可分为
公平锁(按照线程在队列中的排队顺序,先到者先拿到锁)
非公平锁(当线程要获取锁时,无视队列顺序直接去抢锁,谁抢到就是谁的)
static ReentrantLock reentrantLock = new ReentrantLock(true); public static void main(String[] args) { Task task = new Task(); Thread t1 = new Thread(task); Thread t2 = new Thread(task); Thread t3 = new Thread(task); t1.start(); t2.start(); t3.start(); } static class Task implements Runnable{ @Override public void run() { try { reentrantLock.lock(); System.out.println(Thread.currentThread().getName() + "获得lock"); } finally { reentrantLock.unlock(); System.out.println(Thread.currentThread().getName() + "释放lock"); } } } 结果: Thread-0获得lock Thread-0释放lock Thread-1获得lock Thread-1释放lock Thread-2获得lock Thread-2释放lock
Share(共享):
同一时间多个线程可同时执行;
如Semaphore/CountDownLatch。Semaphore、CountDownLatCh、 CyclicBarrier、ReadWriteLock
public static void main(String[] args) { Semaphore semaphore = new Semaphore(10); Task task = new Task(semaphore); Thread t1 = new Thread(task); Thread t2 = new Thread(task); Thread t3 = new Thread(task); t1.start(); t2.start(); t3.start(); } static class Task implements Runnable{ private Semaphore semaphore; Task(Semaphore semaphore){ this.semaphore = semaphore; } @Override public void run() { try { semaphore.acquire(); System.out.println(Thread.currentThread().getName() + "获得许可,剩余许可:" + semaphore.availablePermits()); } catch (InterruptedException e) { e.printStackTrace(); }finally { semaphore.release(); System.out.println(Thread.currentThread().getName() + "释放许可,剩余许可:" + semaphore.availablePermits()); } } public Semaphore getSemaphore() { return semaphore; } public void setSemaphore(Semaphore semaphore) { this.semaphore = semaphore; } } 结果: Thread-1获得许可,剩余许可:8 Thread-2获得许可,剩余许可:7 Thread-0获得许可,剩余许可:8 Thread-2释放许可,剩余许可:9 Thread-1释放许可,剩余许可:8 Thread-0释放许可,剩余许可:10
模板方法设计模式
使用者继承AbstractQueuedSynchronizer并重写指定的方法。
(这些重写方法很简单,无非是对于共享资源state的获取和释放) 将AQS组合在自定义同步组件的实现中,并调用其模板方法,而这些模板方法会调用使用者重写的方法;
// Attempts to acquire in exclusive mode protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException(); } // Attempts to set the state to reflect a release in exclusive mode. protected boolean tryRelease(int arg) { throw new UnsupportedOperationException(); } // Attempts to acquire in shared mode. protected int tryAcquireShared(int arg) { throw new UnsupportedOperationException(); } // Attempts to set the state to reflect a release in shared mode. protected boolean tryReleaseShared(int arg) { throw new UnsupportedOperationException(); }
线程队列数据结构
使用CLH(Craig,Landin,and Hagersten)队列(
一个虚拟的双向链表队列);
(虚拟的双向队列即 不存在队列实例,仅存在结点之间的关联关系)。
AQS是将每条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node)来实现锁的分配;
队列是 双向链表,包括head结点和tail结点,head结点主要用作后续的调度;