1. Introduction
- Is the full name of AQS AbstractQueuedSynchronizer, its location is for almost all the locks in Java and synchronizer provides a basic framework.
- AQS is based on FIFO queue implementation, and internal maintenance of a state variable state, through atomic update of the state variable state can be unlocked operation.
2. Main inner class Node
static final class Node {
// Indicates that a node is in shared mode
static final Node SHARED = new Node();
// Indicates that a node is mutually exclusive
static final Node EXCLUSIVE = null;
// Indicates that the thread is canceled (indicating that the current node is canceled)
static final int CANCELLED = 1;
// Indicates that the current node needs to wake up its successor.
static final int SIGNAL = -1;
// Indicates that threads are waiting on a condition
static final int CONDITION = -2;
// indicate that the following shared lock needs to be propagated unconditionally (shared lock needs to wake up the reading thread continuously)
static final int PROPAGATE = -3;
// Wait state corresponding to the thread saved by the current node (node state optional values: 0, SIGNAL, CANCELLED, CONDITION, PROPAGATE)
// waitStatus == 0 Default status
// waitStatus > 0 cancels the status
// waitStatus == -1 indicates that if the current node is the head node, it needs to wake up its successor after releasing the lock
volatile int waitStatus;
// The first node (precursor) is used for node to build the FIFO queue ~
volatile Node prev;
// Last node (back drive) : used for node to build FIFO queue ~
volatile Node next;
// The thread wrapped by the current node
volatile Thread thread;
// The next node waiting on the Condition (used when Condition locks)
Node nextWaiter;
// Whether the mode is shared
final boolean isShared(a) {
return nextWaiter == SHARED;
}
// Get the previous node
final Node predecessor(a) throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
// Node constructor
Node() { // Used to establish initial head or SHARED marker
}
// Node constructor
Node(Thread thread, Node mode) { // Used by addWaiter
// Shared mode or mutually exclusive mode is stored in the nextWaiter field
this.nextWaiter = mode;
this.thread = thread;
}
// Node constructor
Node(Thread thread, int waitStatus) { // Used by Condition
// The waiting state, used in Condition
this.waitStatus = waitStatus;
this.thread = thread; }}Copy the code
Double-linked list structure, node stores the current thread, the previous node, the next node and thread status information.
3. Main attributes
At any time, the thread corresponding to the header is the current thread holding the lock ~
private transient volatile Node head;
// queue tail :(the blocking queue does not contain the head node, head. Next, tail.)
private transient volatile Node tail;
// Control the lock unlock state variable
// In exclusive mode: 0 indicates the unlocked state, and >0 indicates the locked state
private volatile int state;
Copy the code
Defines a state variable to control lock unlocking and a queue to place waiting threads.
Note: Use the volatile keyword for these variables because you are operating in a multithreaded environment and want their values to be immediately visible to other threads.
These changes are handled directly using the broadening class:
// Get an instance of the Unsafe class. Note that this is for JDK use only, and not for ordinary users
private static final Unsafe unsafe = Unsafe.getUnsafe();
// The offset of the state variable state
private static final long stateOffset;
// The offset of the head node
private static final long headOffset;
// The offset of the tail node
private static final long tailOffset;
// Wait state offset (Node property)
private static final long waitStatusOffset;
// The offset of the next Node (Node attributes)
private static final long nextOffset;
static {
try {
// Get the offset of state
stateOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("state"));
// Get the offset of head
headOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("head"));
// Get the offset of tail
tailOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
// Get the offset of waitStatus
waitStatusOffset = unsafe.objectFieldOffset
(Node.class.getDeclaredField("waitStatus"));
// Get the offset of next
nextOffset = unsafe.objectFieldOffset
(Node.class.getDeclaredField("next"));
} catch (Exception ex) { throw newError(ex); }}// Call the Unsafe method atom to update state
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
Copy the code
4. Superclass attributes
AQS also USES its parent class AbstractOwnableSynchronizer some properties:
// In exclusive mode: indicates that the thread holding the lock is ~
private transient Thread exclusiveOwnerThread;
Copy the code