AbstractQueuedSynchronizer(AQS)源码解析(一)

在JDK1.5版本,新增了并发包,其中包含了显示锁、并发容器。在这些锁和容器里,都有同步器(AQS)的身影。为了更好地理解JDK的并发包,我会用三个主题来详细描述AbstractQueuedSynchronizer的实现。

在AQS中,涉及到同步队列以及Condition对象,这也是我为什么要用三个主题来讲述的原因。本节将主要讲述同步队列,后面两节会分别讲述Condition对象以及AQS的主要功能实现。

AQS同步队列的主要功能是将无法获得资源的线程放入同步队列中,进行等待,它是通过链表来实现的,每一个节点对应一个任务线程。在AbstractQueuedSynchronizer类中用静态内部类Node来作为链表的数据结构。

    static final class Node {
        /* 节点状态 */
        static final int CANCELLED =  1;
        static final int SIGNAL    = -1;
        static final int CONDITION = -2;
        static final int PROPAGATE = -3;
        /* 两种模式 */
        static final Node SHARED = new Node();
        static final Node EXCLUSIVE = null;

        /* 节点状态 */
        volatile int waitStatus;

        /* 模式 */
        Node nextWaiter;

        /* 前一个节点 */
        volatile Node prev;

        /* 后一个节点 */
        volatile Node next;

        /* 对应线程 */
        volatile Thread thread;

        /**
         * Returns true if node is waiting in shared mode
         */
        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        /**
         * Returns previous node, or throws NullPointerException if
         * null.  Use when predecessor cannot be null.
         * @return the predecessor of this node
         */
        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;
        }
    }

Node中有两个字段:waitStatus、nextWaiter。

对于nextWaiter,在同步队列中,该字段会用与模式的区分:SHARED(共享)、EXCLUSIVE(排他)。

对于waitStatus,取值可以是:SIGNAL、CANCELLED、CONDITION、PROPAGATE、0。

1、SIGNAL:后继节点将被或者已经被阻塞,所以当前节点在释放或者取消时,需要unpark它的后继节点。

2、CANCELLED:节点因为超时或者中断被取消。该状态不会再发生变,而且被取消节点对应的线程不会再发生阻塞。

3、CONDITION:该状态仅供在条件队列中的节点使用。当该节点转移到同步队列中时,该状态将被设置为0。

4、PROPAGATE:仅在共享模式下使用。在doReleaseShared()方法中,仅仅会设置头节点的状态为PROPAGATE。

5、0:除以上场景外的其他情况,状态均设置为0。

Node有两个构造方法:

1、在添加等待节点时,初始化线程和模式。

2、在添加条件队列的节点时,初始化线程和CONDITION状态。

以上就是Node的实现,后面的章节会继续介绍Node在AQS中的使用,敬请关注。





AbstractQueuedSynchronizer(AQS)源码解析(一)

时间: 2024-11-10 23:02:09

AbstractQueuedSynchronizer(AQS)源码解析(一)的相关文章

Java 并发之AbstractQueuedSynchronizer(AQS)源码解析

关键字:CLH,Node,线程,waitStatus,CAS,中断 目录 图解AQS的操作细节 0.前言 1.基本概念 1.1.CAS自旋 1.2.Node 1.3.CLH & AQS 1.4.ReentrantLock 2.图解AQS 2.1.线程A单独运行 2.2.线程B开始运行 2.3.线程C开始运行 2.4.线程A停止运行,线程B继续运行 2.5.1.线程B停止运行,线程C继续运行 2.5.2.线程C放弃竞争 3.问题总结 3.1.为什么在unparkSuccessor操作中从尾节点开始

AQS源码解析

文大篇幅引用自HongJie大佬的一行一行源码分析清楚AbstractQueuedSynchronizer,这只是一篇简单的个人整理思路和总结(倒垃圾),如果觉得有些难懂的话,不要犹豫也不要疑惑,很明显是我这篇文章的问题,不是你的问题,这时你最好直接转去看HongJie大佬的原文,那个会好懂很多.还是看不懂的话建议隔一段时间再看,然后像我一样写(复制)一篇总结捋一下思路,加油! AQS 结构 属性 private transient volatile Node head; private tra

AQS源码解析(一)-AtomicBoolean源码解析

基本类: AtomicInteger AtomicLong AtomicBoolean 数组类型: AtomicIntegerArray AtomicLongArray AtomicReferenceArray 介绍 由于在多线程条件下,如果对共享变量修改容易造成数据不一致的情况,所以对于共享变量需要保证线程安全有有如下几种方式: 使用lock或者synchronized进行同步共享变量 使用CAS方法来保证修改变量为原子性操作 该类为后者,基于CAS方式修改具有原子性. 实现原理 将boole

AQS源码解析(1)-CLH

目录 AQS解析 一.简介 二.同步的状态和基本属性 三.入队 addWaiter 3.1 基本步骤介绍 3.2 addWaiter() 3.3 enq(Node node) 四.出队 参考 AQS解析 一.简介 Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO)

源码解析之AQS源码解析

要理解Lock首先要理解AQS,而要理解并发类最好的方法是先理解其并发控制量不同值得含义以及该类运作流程,然后配合一步步看源码.该类有一个重要的控制量是WaitStates. /** waitStatus value to indicate thread has cancelled */ static final int CANCELLED = 1; //该节点被取消了 /** waitStatus value to indicate successor's thread needs unpar

AbstractQueuedSynchronizer源码解析

1.简介 AbstractQueuedSynchronizer队列同步器,用来实现锁或者其他同步组件的基础框架 AbstractQueuedSynchronizer使用int类型的volatile变量维护同步状态 一般使用AQS的主要方式是继承,子类通过实现它提供的抽象方法来管理同步状态,主要管理的方式是通过tryAcquire和tryRelease类似的方法来操作状态,同时,AQS提供以下线程安全的方法来对状态进行操作 protected final int getState() { retu

Java concurrent AQS 源码详解

一.引言 AQS(同步阻塞队列)是concurrent包下锁机制实现的基础,相信大家在读完本篇博客后会对AQS框架有一个较为清晰的认识 这篇博客主要针对AbstractQueuedSynchronizer的源码进行分析,大致分为三个部分: 静态内部类Node的解析 重要常量以及字段的解析 重要方法的源码详解. 所有的分析仅基于个人的理解,若有不正之处,请谅解和批评指正,不胜感激!!! 二.Node解析 AQS在内部维护了一个同步阻塞队列,下面简称sync queue,该队列的元素即静态内部类No

FutureTask 源码解析

FutureTask 源码解析 版权声明:本文为本作者原创文章,转载请注明出处.感谢 码梦为生| 刘锟洋 的投稿 站在使用者的角度,future是一个经常在多线程环境下使用的Runnable,使用它的好处有两个:1. 线程执行结果带有返回值2. 提供了一个线程超时的功能,超过超时时间抛出异常后返回. 那,怎么实现future这种超时控制呢?来看看代码: FutureTask的实现只是依赖了一个内部类Sync实现的,Sync是AQS (AbstractQueuedSynchronizer)的子类,

CountDownLatch源码解析

一.CountDownLatch介绍 CountDownLatch是在jdk1.5被引入的,它主要是通过一个计数器来实现的,当在初始化该类的构造函数时,会事先传入一个状态值,之后在执行await方法后, 在这个状态值为0之前,当前线程(指的是调用await的线程)会一直等待.它内部使用了AQS来实现的,且是共享锁,具体怎么实现,待会看看它的实现原理. 它的应用场景: 一般在于在执行当前线程之前,要完成n个线程的任务,才能执行当前线程.这种场景适合用countdownLatch. 二.源码解析 先