【JUC】11.AQS

导读:本篇文章讲解 【JUC】11.AQS,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

1. AQS是什么

AQS是指AbstractQueuedSynchronizer

AQS是用来实现锁或者其他同步器组件的公共基本部分的抽象实现,是重量级基础框架及整个JUC体系的基石,主要用于解决锁分配给“谁”的问题

整体就是一个抽象的FIFO队列来完成资源获取线程的排队工作,并通过一个int类变量表示持有锁的状态


2. AQS是JUC框架基础

在前面用到的ReentrantLock、CountDownLatch等底层都与AQS有关

Java并发大神DougLee,提出统一规范并简化了锁的实现,将其抽象出来屏蔽了同步状态管理、同步队列的管理和维护、阻塞线程排队和通知、唤醒机制等,是一切锁和同步组件实现的——–公共基础部分

在这里插入图片描述

就像这样的业务,加锁使得state修改为1,告诉其他线程有人正在使用,其他线程在等候区阻塞,有阻塞就需要排队,实现排队就必然需要队列,那么接下来谁获取锁,谁不能获取锁,这一系列规范都由AQS实现。

抢到资源的线程直接使用处理业务,抢不到资源的必然涉及一种排队等候机制。抢占资源失败的线程继续去等待(类似银行业务办理窗口都满了暂时没有受理窗口的顾客只能去候客区排队等候),但等候线程仍然保留获取锁的可能上获取锁流程仍在继续(候客区的顾客也在等着叫号,轮到了再去受理窗口办理业务)。

既然说到了排队等候机制,那么就一定会有某种队列形成,这样的队列是什么数据结构呢?

如果共享资源被占用,就需要一定的阻塞等待唤醒机制来保证锁分配。这个机制主要用的是CLH队列的变体实现的,将暂时获取不到锁的线程加入到队列中,这个队列就是AQS同步队列的抽象表现。它将要请求共享资源的线程及自身的等待状态封装成队列的结点对象(Node),通过 CAS、自以及LockSupportpark()的方式,维护state变量的状态,使并发达到同步的效果。

在这里插入图片描述


3. AQS能干嘛

public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements java.io.Serializable {

    private static final long serialVersionUID = 7373984972572414691L;

    static final class Node {
        /** Marker to indicate a node is waiting in shared mode */
        static final Node SHARED = new Node();
        /** Marker to indicate a node is waiting in exclusive mode */
        static final Node EXCLUSIVE = null;

        static final int CANCELLED =  1;
        static final int SIGNAL    = -1;
        static final int CONDITION = -2;

        static final int PROPAGATE = -3;

        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;
        }
    }

    private transient volatile Node head;

    private transient volatile Node tail;

    private volatile int state;


    protected final int getState() {
        return state;
    }

}

AQS内部有个Node类,并有头指针和尾指针,AQS里面真正干活的是Node

AQS使用一个volatile的int类型的成员变量来表示同步状态,通过内置的FIFO队列来完成资源获取的排队工作将每条要去抢占资源的线程封装成一个Node节点来实现锁的分配,通过CAS完成对State值的修改。

在这里插入图片描述


4. AQS内部体系架构

在这里插入图片描述


4.1 AQS的int变量

AQS内部有一个state成员变量以及它的get和set方法

这个整型变量的作用是告诉其他线程是否有人在占用资源

如果没有其他线程就可以竞争获取到资源类

如果有,其他线程则需要在等候区等待资源空闲


4.2 AQS的CLH队列

在这里插入图片描述

CLH队列是一个双向节点,分别有指向该节点前面的指针和指向该节点后面的指针


4.3 Node

AQS中内部类Node可以理解为银行排队等候的凳子,等候的线程存在这个Node中

Node中有一个名为waitState成员变量,是指等待状态

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;
    }
}

参考:尚硅谷2022版JUC并发编程(对标阿里P6-P7)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/94974.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!