“This is the 18th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

AQS features and nouns

  • Fair lock
  • reentrant
  • LockSupport
  • Spin lock (CAS)
  • A linked list of data structures
  • A template approach to design patterns

What is AQS?

Literal interpretation:

Abstract queue synchronizer

Core classes:

  • AbstractOwnableSynchronizer
  • AbstractQueuedLongSynchronizer
  • AbstractQueuedSynchronizer

Usually AbstractQueuedSynchronizer AQS for short

Technical explanation

Is used to build locks and other synchronizer components of the heavyweight infrastructure and the cornerstone of the entire JUC architecture, through the built-in FIFO queue to complete the queuing of resource acquisition threads, and through an int type variable to indicate the status of the lock

Why is AQS the most important cornerstone of JUC content

Related to the class

  • ReentrantLock

  • CountDownLatch

  • ReentrantReadWriteLock

  • Semaphore

Deep understanding of

  • Lock, lock oriented users, the core is to define the program and lock interaction API
  • Synchronizers, lock-oriented implementors such as Java concurrency wizard Doug Lee, come up with the same specification and simplify the implementation of locks, eliminating synchronization state management, blocking thread queuing and notification, wake up mechanisms, and so on.

AQS role

Locking causes blocking

If there is blocking, queue is needed, and some form of queue is necessary to manage queue.

explain

The thread that grabs the resource directly uses the processing business logic, and the thread that cannot grab the resource must enter a queuing mechanism. Preempted resources failed thread to wait (similar to bank business through the window is full, temporarily not to accept the window customers have to wait to queue waiting guest area), but the waiting thread remains the possibility of acquiring a lock and acquiring a lock process continues (wait the customer is waiting for your turn, turn to acceptance window to handle business).

Now that the queuing mechanism is mentioned. So there must be some sort of queue, and what data structure is that queue?

If shared resources are occupied, some blocking wake-up mechanism is required to ensure lock allocation. This mechanism is implemented mainly through a variant of the CHL queue, which adds threads that temporarily cannot acquire locks to a queue, which is an abstract implementation of AQS. It encapsulates the thread requesting shared resources into a queue Node. Through CAS, spin and locksupport.park (), it maintains the state of sate variables to achieve synchronous control effect of concurrency.

AQS practice

Preliminary understanding of AQS

Blocking requires queuing, and queuing requires queues

AQS uses a volatile int type member variable to represent the synchronization State, and uses the built-in FIFO queue to complete the queuing of resource acquisition. Each thread to preempt resources is encapsulated as a Node Node to realize the allocation of locks, and the modification of State value is completed through CAS.

AQS internal architecture

AQS composition

  • Int variable of AQS

AQS synchronization status State Member variable

    /** * The synchronization state. */
    private volatile int state;
Copy the code

The status of the bank’s processing window

1, 0 means no one, free state can be handled

2, greater than or equal to 1, someone is occupying the window, waiting to go

  • CLH queue for AQS

CLH queue (three big bull names) is a bidirectional queue

Customers wait in the waiting area of the bank

  • A small summary

Queues are needed when there is blocking, and queues are necessary to achieve queuing

State + CLH variant of the two-endian queue

The basic structure of AQS synchronization queue

  • Int variable in Node

The Node waitState member variable

volatile int waitStatus;
Copy the code

To summarize

The wait state of other customers (other threads) in the waiting area

Each queued individual in a queue is a Node

  • Details of the Node class
    static final class Node {
		/ / Shared
        static final Node SHARED = new Node();
        / / exclusive
        static final Node EXCLUSIVE = null;

		// The thread was cancelled
        static final int CANCELLED =  1;
		// Subsequent threads need to wake up
        static final int SIGNAL    = -1;
		// Wait for the condition to wake up
        static final int CONDITION = -2;
		// Shared synchronous state acquisition will propagate unconditionally
        static final int PROPAGATE = -3;

        // The initial state is 0
        volatile int waitStatus;

        // The front node
        volatile Node prev;

        // back node
        volatile Node next;

        // The current thread
        volatile Thread thread;


        Node nextWaiter;


        final boolean isShared(a) {
            return nextWaiter == SHARED;
        }


        final Node predecessor(a) throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() {    // Used to establish initial head or SHARED marker
        }

        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; }}Copy the code

The basic structure of AQS synchronization queue