AQS simply go through

foreword

Looking back at the front:

Only the bald head can become stronger!

Originally, I planned to write the subclass implementation of Lock in this chapter, but seeing such a concept of AQS, it can be said that the subclass implementation of Lock is based on AQS .

AQS I have also seen him in the interview questions, but I have no idea what it is. So in this article, I will talk about the AQS thing, at least know what its concept is, right~

Then let's start~

1. What is AQS?

First of all, let's popularize what juc is: juc is actually the abbreviation of package (java.util.concurrnt)

  • Don't be fooled into thinking that juc is something awesome. Actually, it's just a bag

We can find that there are three abstract classes under the lock package:

  • AbstractOwnableSynchronizer
  • AbstractQueuedLongSynchronizer
  • AbstractQueuedSynchronizer

Usually: AbstractQueuedSynchronizer is abbreviated as AQS

Two common locks like our Lock are implemented based on it:

So let's take a look at what the AbstractQueuedSynchronizer is. The fastest way to see what a class does is to look at its top comment

After reading it through, you can summarize the following key information:

  • AQS is actually a framework that can implement locks for us
  • The key to the internal implementation is: first-in-first-out queue, state state
  • Defines the inner class ConditionObject
  • Has two thread modes
    • exclusive mode
    • shared mode
  • The related locks in the LOCK package (commonly used are ReentrantLock, ReadWriteLock) are built based on AQS
  • Generally we call AQS the synchronizer

Second, a simple look at AQS

It was also mentioned above that the most important things in AQS are the status and queue. Let's see what the source code looks like next...

2.1 Synchronization status

Use volatile decoration to achieve thread visibility:

When modifying the state value, use the CAS algorithm to achieve:

2.2 FIFO queue

This queue is called: CLH queue (composed of three names), it is a two-way queue

Look at the composition of its queue source code:


    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;

        // 等待condition唤醒
        static final int CONDITION = -2;

        // 共享式同步状态获取将会无条件地传播下去(没看懂)
        static final int PROPAGATE = -3;


        // 初始为0,状态是上面的几种
        volatile int waitStatus;

        // 前置节点
        volatile Node prev;

        // 后继节点
        volatile Node next;


        volatile Thread thread;


        Node nextWaiter;

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


        final Node predecessor() 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;
        }
    }

2.3Acquire method

The process of acquiring an exclusive lock is defined in acquire, which uses the template design pattern and is implemented by subclasses~

Procedure: acquire(int) tries to acquire the resource, if the acquisition fails, insert the thread into the waiting queue. After inserting into the waiting queue, acquire(int) does not give up the acquisition of resources, but judges whether it should continue to acquire resources according to the status of the front node. If the front node is the head node, continue to try to acquire resources. If the front node is SIGNAL state, interrupt the current thread, otherwise continue to try to obtain resources. Until the current thread is park() or acquires resources, acquire(int) ends.

source:

2.4 release method

The process of releasing the exclusive lock is defined in acquire, which also uses the template design pattern , which is implemented by subclasses~

Process: First call the tryRelease() method of the subclass to release the lock, and then wake up the successor node. During the wake-up process, it is necessary to judge whether the successor node satisfies the situation. If the successor node is not in the state of invalidation, wake up the successor node, otherwise Find a suitable node forward from the tail node, and wake up if found.

source:

3. Finally

To summarize what AQS is:

  • Many of the blocking classes in the juc package are built on AQS
    • AQS can be said to be a framework for implementing synchronization locks and synchronizers . Many implementation classes are built on its basis.
  • The default implementation of the waiting queue is implemented in AQS, and the subclass can implement it by rewriting part of the code ( a lot of template code is used )

Interested students can go to the source code and the link below to continue learning, I will not describe it here. Simply go through AQS again~

Tomorrow, we will see the implementation of Lock's explicit lock ~~~

References:

If there are any mistakes in the article, please correct me, and we can communicate with each other. Students who are used to reading technical articles on WeChat and want to get more Java resources can follow WeChat public account: Java3y . For everyone's convenience, I just created a new QQ group: 742919422 , you can also go to communicate. Thank you for your support! Hope to introduce more to other friends in need

Table of Contents Navigation for Articles :

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324849927&siteId=291194637
AQS
AQS