table of Contents
AQS resolve
I. Introduction
Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues. This class is designed to be a useful basis for most kinds of synchronizers that rely on a single atomic
int
value to represent 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. Given these, the other methods in this class carry out all queuing and blocking mechanics. Subclasses can maintain other state fields, but only the atomically updatedint
value manipulated using methodsgetState()
,setState(int)
andcompareAndSetState(int, int)
is tracked with respect to synchronization.
AQS implemented using a synchronous queue FIFO provides the basic framework for the associated lock and synchronization lock. It integer representation of a state in order to provide a basic skeleton can be used are synchronizers. By AQS subclass method in protected rewritten so as to realize free and acquire the lock, through this form sub-class will be able to have a complete team and into the locking mechanism.
AQS theory used in synchronous FIFO queue implemented had raised from CLH
, that will AQS is talking about the basic implementation of CLH
The wait queue is a variant of a "CLH" (Craig, Landin, and* Hagersten) lock queue. CLH locks are normally used for* spinlocks.
Second, the basic attributes and state synchronization
static final class Node {
/** 共享模式 */
static final Node SHARED = new Node();
/** 独占模式 */
static final Node EXCLUSIVE = null;
/** 标明当前线程已经被取消 */
static final int CANCELLED = 1;
/** 线程的下一个等待线程需要被唤醒 */
static final int SIGNAL = -1;
/** 当前线程正在等待中 */
static final int CONDITION = -2;
/** 下一次的acquire方法应该被无条件的传播*/
static final int PROPAGATE = -3;
/** 当前等待状态*/
volatile int waitStatus;
/** 前驱节点*/
volatile Node prev;
/** 与上面类似 */
volatile Node next;
/** 当前node持有的线程,在构造器中初始化,在退出队列后被置为null*/
volatile Thread thread;
/** 指向当前节点的后面第一个处于CODITION状态的节点,或者为SHARED,只有对于独占式才会有CODTION节点的存 *在,对于共享式的其nextWaiter为SHARED(变量)
*/
Node nextWaiter;
/**
* Returns true if node is waiting in shared mode.
*/
final boolean isShared() {
return nextWaiter == SHARED;
}
/** 返回前驱节点,添加一层封装*/
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() { // 用于创建出事头结点和SHARED标志的构造器
}
Node(Thread thread, Node mode) { // Used by addWaiter
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus) { // Used by Condition
this.waitStatus = waitStatus;
this.thread = thread;
}
}
** synchronization state is divided into five kinds, 0 INITIAL
, 1 CANCELLED
, -1 SINGAL
, -2 CONDITION
, -3 of PROPAGETE**
the role and status information following five states
- SIGNAL: successor node of the node has passed the
LockSupport.part()
method blocks the current node is released or is deleted after its successor nodes need to wake up, to avoid competition between threads, access to resourcesacquire
all methods should be setSIGNAL
flag, then re atomic capturing operation, if the acquisition fails, blocked - CANCELLED: node due to timeout or interruption into the
CANCELLED
state, the node if the state will not enter into other states, the state of the thread will not be blocked - CONDITION: the node is waiting in the queue, he will use as an ordinary node of the synchronization queue (i.e., not be awakened or precursor node
unpark()
), unless he's state is set to 0INITIAL
- PROPAGETE: releasing the shared lock (
releaseShared
) should be passed to other nodes. IndoReleaseShared
the first node is used to ensure the dissemination of information will continue - INITIAL: initial state or intermediate state
These types of states can be distinguished by a more simple: If >0
that is CANCELLED
, <=0
the state that can be used
CLH synchronous queue, the following chart
- prev predecessor node to node, next node is node rear-wheel drive
nextWaiter
Field, saving a mode-locked state (Mode), tryAcquire(int)
and a tryAcquireShared(int)
method of obtaining state by exclusive or shared mode, if it fails to call addWaiter (Node mode) way into the team. nextWaiter is used to indicate that the current form
- SHARED enumeration sharing mode, the value of new Node (), the values are unique, using
static
modified - EXCLUSIVE enumeration exclusive mode, the value of
null
#predecessor()
Way, a Node node before a Node node. In the interior of the method, Node p = prev
the local copy is to avoid the concurrency, prev
judged complete == null
when happens to be modified, in order to ensure thread safety.
Third, the team addWaiter
3.1 Introduction The basic steps
- Generate a new node
node
The new node
node
precursor tail node points to the originaltail
UNSAFE provided by the tail node
tail
to the new nodenode
Provided penultimate node is tail node of the original
old tail
rear-drive nodenext
is tail node newnode
- If it fails by
enq
retry again- If the first node is null, a new node
node
is provided to the head node - No performs an operation similar to Step 2
- If the first node is null, a new node
Use graphical form to describe the team's problems
3.2 addWaiter()
Deep into the addWaiter()
source code view
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// 先进行一次简单的入队尝试
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
3.3 enq (Node node)
enq
Methods and methods addWaiter
consistent , the main difference is that when considering the node does not need to initialize the current node is set to node initializationhead node
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // 如果头部不存在就进行初始化
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;//该步骤和3.2中的步骤类似
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
Fourth, the team
CLH synchronization queue to follow the FIFO, the thread releases the synchronization status of the first node, it will wake up the next node ( Node.next
). The successor node will be successful in obtaining synchronization status, set itself a head node ( head
).
This process is very simple, head
the implementation of the original node and disconnect the first node next
and the current node prev
can be. Note that in this process is the need to use CAS to ensure that , because only one thread can successfully get into sync.
Procedure is as follows:
#setHead(Node node)
Methods to achieve the above-described dequeue logic. code show as below:
private void setHead(Node node) {
head = node; node.thread = null; node.prev = null;
}
reference
- [Java Sike high concurrency] http://www.iocoder.cn/JUC/sike/aqs-0-intro/
- Doug Lea: "Java Concurrent Programming real"