JUC之 AbstractQueuedSynchronizer之AQS

AQS

抽象队列同步器
是用来构建锁或者其它同步器组件的公共基础部分的抽象实现,是重量级基础框架及整个JUC体系的基石,主要解决锁分配给谁的问题通过内置的抽象FIFO队列来完成资源获取线程的排队工作,并通过一个int类变量表示持有锁的状态;
JUC之 AbstractQueuedSynchronizer之AQS_第1张图片

为什么说AQS是JUC的基石

  1. 提供了底层的同步原语:AQS 提供了底层的同步原语,如锁、信号量、倒计时门栓等,可以作为其他高级同步工具的基础。通过 AQS,开发人员可以实现各种类型的同步器,从简单的互斥锁到复杂的并发数据结构,为并发编程提供了强大的基础。
  2. 丰富的同步器工具类:JUC 库中许多同步器工具类(如 ReentrantLock、CountDownLatch、Semaphore 等)都是基于 AQS 实现的。AQS 提供了一组丰富的方法和状态管理机制,使得开发人员可以相对容易地实现自定义的同步器。这些同步器工具类提供了更高级别、更方便使用的同步控制方法,使得并发编程更加简单、灵活和高效。
  3. 支持独占和共享模式:AQS 提供了对独占模式和共享模式的支持。独占模式适用于只允许一个线程访问临界区的场景,而共享模式适用于允许多个线程同时访问临界区的场景。AQS 的设计灵活性使得它能够适应不同类型的并发问题,并提供了对应的同步策略。
  4. 可扩展性和灵活性:AQS 的内部使用了一个双向链表(CLH 队列)来管理等待线程,可以实现公平或非公平的线程调度机制,使得各种同步场景都能够得到良好的性能和灵活性。开发人员可以通过继承 AQS 类来实现自定义的同步器,根据具体需求定制同步策略。

AQS基础

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

state

AQS的同步状态State成员变量
JUC之 AbstractQueuedSynchronizer之AQS_第2张图片

Node

在AQS类内部
JUC之 AbstractQueuedSynchronizer之AQS_第3张图片

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;
    /**
         * waitStatus value to indicate the next acquireShared should
         * unconditionally propagate
         */
    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;
    }
}

属性说明

JUC之 AbstractQueuedSynchronizer之AQS_第4张图片

架构

JUC之 AbstractQueuedSynchronizer之AQS_第5张图片

AQS同步队列的基本结构

JUC之 AbstractQueuedSynchronizer之AQS_第6张图片
CLH:Craig、Landin and Hagersten 队列,是个单向链表,AQS中的队列是CLH变体的虚拟双向队列(FIFO)

AQS源码解读

从ReentrantLock开始

JUC之 AbstractQueuedSynchronizer之AQS_第7张图片
ReentrantLock有两种实现方式:公平锁和非公平锁;
JUC之 AbstractQueuedSynchronizer之AQS_第8张图片

公平锁

JUC之 AbstractQueuedSynchronizer之AQS_第9张图片

非公平锁

JUC之 AbstractQueuedSynchronizer之AQS_第10张图片
从源码可以看出公平锁和非公平锁的实现区别在与hasQueuedPredecessors()方法

hasQueuedPredecessors()

JUC之 AbstractQueuedSynchronizer之AQS_第11张图片
hasQueuedPredecessors方法用于排序当前队列中是否含有有效节点;
如果当前队列中含有有效的节点公平锁会将其放入队列总等待,保证“先来先到”的规则;

从非公平锁的源码开始

JUC之 AbstractQueuedSynchronizer之AQS_第12张图片

acquire

JUC之 AbstractQueuedSynchronizer之AQS_第13张图片

tryAcquire
nonfairTryAcquire

JUC之 AbstractQueuedSynchronizer之AQS_第14张图片

  • state同步状态 == 0 为无锁状态,当前线程抢占锁,成功返回true 反之返回false;
  • state同步状态 != 0 时判断持有锁的线程是否为当前线程,如果时则state加一返回true(可重入性)否则返回false;

addWaiter

JUC之 AbstractQueuedSynchronizer之AQS_第15张图片

  • 构建线程节点
  • 如果当前的尾节点存在,则将当前线程节点设置为尾节点并返回;
  • 否则进入enq进行初始化首尾节点(哨兵节点);
enq

加入队列
JUC之 AbstractQueuedSynchronizer之AQS_第16张图片

  • 如果当前队列的tail不存在,构造新节点,并赋值给head和tail;
  • 第二次循环,将当前线程节点设置为尾节点并返回;

acquireQueued

JUC之 AbstractQueuedSynchronizer之AQS_第17张图片

  • 判断当前线程节点的前驱节点是否等与头节点 和 尝试抢占锁,当都为true时设置当前线程节点为头节点;
shouldParkAfterFailedAcquire

判断当前线程是否挂起
JUC之 AbstractQueuedSynchronizer之AQS_第18张图片

  • 前驱节点的waitStatus为Node.SIGNAL时返回true;
  • 前驱节点的waitStatus大于0时,表示前驱节点已取消,并将该节点从队列中移除;
  • 将前驱节点的waitStatus修改为Node.SIGNAL状态;
parkAndCheckInterrupt

线程挂起
JUC之 AbstractQueuedSynchronizer之AQS_第19张图片

你可能感兴趣的:(JUC,java,JUC,AQS,源码解析,Lock锁)