What are the waitStatus

// CANCELLED: This object was CANCELLED due to timeout or interruption. Once a node is canceled, it does not change state. In particular, threads that cancel nodes are no longer blocked.
static final int CANCELLED =  1;
// SIGNAL: The node behind this node has been (or is about to be) blocked (via park), so the current node must disconnect the node behind it when releasing or canceling
// To avoid contention, the preceding node must be in SIGNAL state when acquire method, retry atomic Acquire, and then block on failure.
static final int SIGNAL    = -1;
// This object is currently in the conditional queue. Nodes marked CONDITION are moved to a special conditional wait queue (at which point the state is set to 0) and are not moved back to the synchronous wait queue until CONDITION. (The use of this value here is unrelated to the other use of the field, but simplifies the mechanism.)
static final int CONDITION = -2;
// Propagation: releaseShared should be propagated to other nodes. This is set in doReleaseShared (for header nodes only) to ensure propagation continues, even if other operations intervene later.
static final int PROPAGATE = -3;

//0: The above values are not arranged numerically to simplify use. A non-negative value means that the node does not need to emit signals. So, most code doesn't need to check for specific values, just symbols.
// For normally synchronized nodes, this field is initialized to 0; For condition nodes, this field is initialized as a condition. It is modified using CAS (or written with unconditional volatile if possible).
Copy the code

SIGNAL

As you can see from the above comments, the current node can be woken up by the previous node only if the previous node is SIGNAL.

Conclusion:

  1. If only one thread comes in, CHL synchronization will not initialize the strip queue
  2. When the second thread fails to lock (contention), it initializes a node for the head node and suspends its own node behind the head node
  3. Each waiting node changes the status of the previous node to SIGNAL(-1), which indicates that the next node can be woken up
  4. If the state of the head node is not 0 when the lock is released, it is set to 0 first. Then wake up the next node
  5. Nodes CANCELLED at WS >0 will be skipped for enqueueing and awakening
  6. The head node must represent the thread node that is currently acquiring the lock.

CANCELLED

This object was cancelled due to timeout or interruption. Once a node is canceled, it does not change state. In particular, threads that cancel nodes are no longer blocked.

Start with the interrupt thread case:

public class NonFairReentrantLock extends AbstractQueuedSynchronizer {

    public static void main(String[] args) {

        final ReentrantLock lock = new ReentrantLock();

        List<Thread> threads = new ArrayList<>(10);
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread("Thread:" + i) {
                @Override
                public void run(a) {
                    try {
                        lock.lockInterruptibly(); // An exception is raised here if the thread is interrupted
                        // ... method body
                        System.out.println(Thread.currentThread().getName() + "Execute!");
                        Thread.sleep(100);
                        System.out.println(Thread.currentThread().getName() + "Execution complete!");
                    } catch (InterruptedException e) {
                        // This handles subsequent logic for thread interrupts
                        System.out.println(Thread.currentThread().getName() + "Interrupted!);
                    } finally{ lock.unlock(); }}}; threads.add(thread); thread.start(); }// The thread is marked with an interrupt flag
        threads.get(3).interrupt();
        // Main thread is blockedLockSupport.park(); }}Copy the code

Output result:

Thread:0Start executing! Exception in thread"Thread: 3" java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151Thread) :3Be interrupted! at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
	at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
	at concurrent.reentrantLockDemo.NonFairReentrantLock$1.run(NonFairReentrantLock.java:30Thread) :0Execution complete! Thread:1Start executing! Thread:1Execution complete! Thread:2Start executing! Thread:2Execution complete! Thread:4Start executing! Thread:4Execution complete! Thread:5Start executing! Thread:5Execution complete! Thread:6Start executing! Thread:6Execution complete! Thread:7Start executing! Thread:7Execution complete! Thread:8Start executing! Thread:8Execution complete! Thread:9Start executing! Thread:9Execution complete!Copy the code

There are two ways to write a blog

CONDITION

Consider the BlockingQueue example

PROPAGATE

Semaphore case description