AbstractQueuedSynchronizer 独占式源码阅读

概述

● 一个int成员变量 state 表示同步状态
● 通过内置的FIFO队列来完成资源获取线程的排队工作

属性

AbstractQueuedSynchronizer属性

   /**
     * 同步队列的头节点     
     */
    private transient volatile Node head;

    /**
     * 同步队列尾节点,enq 加入
     */
    private transient volatile Node tail;

    /**
     * 同步状态
     */
    private volatile int state;

    /**
     * 获取状态
     */
    protected final int getState() {
        return state;
    }

    /**
     * 设置状态
     */
    protected final void setState(int newState) {
        state = newState;
    }

    /**
     * CAS 设置状态
     */
    protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

    /**
     * The number of nanoseconds for which it is faster to spin
     * rather than to use timed park. A rough estimate suffices
     * to improve responsiveness with very short timeouts.
     */
    static final long spinForTimeoutThreshold = 1000L;

Node 节点属性

 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;
        
        // 值为-2, 节点在等待队列, 当其他线程 signal(),从等待队列中移除到同步队列中 |
        static final int CONDITION = -2;
        
        // 值为-3, 下一次共享获取同步状态将会无条件传播下去
        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;
        }
    }

常用方法

同步状态的三个方法:
● getState() 获取同步状态
● setState(int newState) 设置当前同步状态
● compareAndSetState(int expect, int update) CAS设置同步状态,原子操作

AbstractQueuedSynchronizer可重写的方法:

方法名称方法描述
boolean tryAcquire(int arg)独占式获取同步状态,查询当前状态是否符合预期,并且CAS设置
boolean tryRelease(int arg)独占式释放同步状态,释放后,等待获取同步状态的线程有机会获取同步状态
int tryAcquireShared(int arg)共享式获取同步状态,如果大于等于0,表示获取成功
boolean tryReleaseShared(int arg)共享式释放同步状态
boolean isHeldExclusively()在独占模式下被线程占用,表示是否被当前线程独占

AbstractQueuedSynchronizer提供的模版方法

方法名称方法描述
boolean acquire(int arg)独占式获取同步状态, 成功返回, 失败队列等待, 调用tryAcquire()
boolean acquireInterruptibly(int arg)acquire 相同, 但是可以中断
int tryAcquireNanos(int arg, long nanos)acquireInterruptibly 基础上增加了超时限制, 超时返回false, 返回true
acquireShared(int arg)共享式获取同步状态, 和acquire差不多, 区别是同一时刻可以有多个线程获取同步状态
acquireSharedInterruptibly(int arg)acquireShared 相同, 但是可以中断
int tryAcquireSharedInterruptibly(int arg, long nanos)acquireSharedInterrup

流程图

在这里插入图片描述

流程图主要方法源码阅读

acquire

独占式获取同步状态, 成功返回, 失败队列等待

public final void acquire(int arg) {
    // tryAcquire获取信号量
    // 如果失败 tryAcquire(arg)=false addWaiter入队列、acquireQueued 排队获取锁
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            // 前一个节点是头节点 尝试获取锁 获取锁成功 设置自己为头节点 
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }

           // 前面节点设置为 singal,自己就可以睡眠了
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                // 被中断 尝试获取信号量
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

addWaiter

节点进入同步队列

    private Node addWaiter(Node mode) {
        // 创建节点
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        // 尾节点不为空
        if (pred != null) {
            // 设置当前节点的前一个节点为尾节点
            node.prev = pred;
            // cas 设置自己为尾节点
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        // 尾节点为空 或 cas 设置自己为尾节点失败了
        enq(node);
        return node;
    }
    
    /**
     * 入队
     */
    private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
           // 尾节点为空,设置新的头节点
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                // 设置当前节点的前一个节点为尾节点
                node.prev = t;
                // cas 设置自己为尾节点
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

shouldParkAfterFailedAcquire

前面节点设置为 singal,设置成功返回true,失败false

 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        // 前面的节点SIGNAL自己就可以park了
        if (ws == Node.SIGNAL)
            return true;
        if (ws > 0) {
            // 找到第一个不是取消状态的节点
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            /*
             * 设置 WaitStatus SIGNAL
             */
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

parkAndCheckInterrupt

   private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

acquireInterruptibly

acquire 相同, 但是可以中断

 public final void acquireInterruptibly(int arg)
            throws InterruptedException {
        // 被中断抛出InterruptedException
        if (Thread.interrupted())
            throw new InterruptedException();
        if (!tryAcquire(arg))
            doAcquireInterruptibly(arg);
    }
    
private void doAcquireInterruptibly(int arg)
    throws InterruptedException {
    final Node node = addWaiter(Node.EXCLUSIVE);
    boolean failed = true;
    try {
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                // 被中断抛出InterruptedException
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }

tryAcquireNanos

acquireInterruptibly 基础上增加了超时限制, 超时返回false, 返回true

   public final boolean tryAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquire(arg) ||
            doAcquireNanos(arg, nanosTimeout);
    }
    
    private boolean doAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        final long deadline = System.nanoTime() + nanosTimeout;
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return true;
                }
                nanosTimeout = deadline - System.nanoTime();
                // 超时返回false
                if (nanosTimeout <= 0L)
                    return false;
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    // park指定时间
                    LockSupport.parkNanos(this, nanosTimeout);
                // 中断抛出异常
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

release

释放信号量, 如果头节点不为空 状态为SINGAL, 唤醒头节点的下一个节点

public final boolean release(int arg) {
    if (tryRelease(arg)) {
        // 释放arg信号量成功
        Node h = head;
        // 如果头节点不为空 状态为SINGAL, 唤醒头节点的下一个节点
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

private void unparkSuccessor(Node node) {
    int ws = node.waitStatus;
    // 唤醒先修改waitStatus从SINGAL->0初始化
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);

    // 找到node之后第一个不被取消的节点, LockSupport.unpark唤醒该节点
    Node s = node.next;
    if (s == null || s.waitStatus > 0) {
        s = null;
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    if (s != null)
        LockSupport.unpark(s.thread);
}

参考文献

  • Java并发编程的艺术第二版 方腾飞、魏鹏、程晓明

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/483031.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

docker 数据卷 (二)

1&#xff0c;为什么使用数据卷 卷是在一个或多个容器内被选定的目录&#xff0c;为docker提供持久化数据或共享数据&#xff0c;是docker存储容器生成和使用的数据的首选机制。对卷的修改会直接生效&#xff0c;当提交或创建镜像时&#xff0c;卷不被包括在镜像中。 总结为两…

ctfshow web入门 反序列化

254 分析代码&#xff1a; 如果用户名和密码参数都存在&#xff0c;脚本会创建一个 ctfShowUser 类的实例 $user。 接着&#xff0c;调用 $user->login($username, $password) 方法尝试登录。如果登录成功&#xff08;即用户名和密码与类中的默认值匹配&#xff09;&#…

[AutoSar]BSW_ECUC模块介绍

目录 关键词平台说明一、ECUC 的定义 关键词 嵌入式、C语言、autosar、OS、BSW 平台说明 项目ValueOSautosar OSautosar厂商vector &#xff0c; EB芯片厂商TI 英飞凌编程语言C&#xff0c;C编译器HighTec (GCC)autosar版本4.3.1 >>>>>回到总目录<<<…

iOS UIFont-新增第三方字体

背景 在项目中添加三方字体&#xff0c;是在开发中比较常见的需求&#xff0c;每次新增字体&#xff0c;都会遗忘其中某个步骤&#xff0c;又要去百度一下才能把字体添加使用成功。每次这样有点浪费时间和打击自信&#xff0c;于是便想着&#xff0c;自己好好来理一理新增字体…

Penpad 生态资产 $PDD LaunchPad 在即,Season 2 规则解读

Penpad是Scroll上的LauncPad平台&#xff0c;该平台继承了Scroll底层的技术优势&#xff0c;并基于零知识证明技术&#xff0c;推出了系列功能包括账户抽象化、灵活的挖矿功能&#xff0c;并将在未来实现合规为RWA等资产登录Scroll生态构建基础。该平台被认为是绝大多数项目、资…

[RootersCTF2019]I_<3_Flask -不会编程的崽

又是一个新东西哦。先看界面 源代码没提示&#xff0c;抓包没特别数据&#xff0c;没有交互界面&#xff0c;后台扫描也没文件。我知道是python模板&#xff0c;但是注入点&#xff1f;&#xff1f;&#xff1f;看来wp才知道原来还有参数爆破&#xff0c;哈哈哈。整笑了。有一…

怎么拆解台式电脑风扇CPU风扇的拆卸步骤-怎么挑

今天我就跟大家分享一下如何选购电脑风扇的知识。 我也会解释一下机箱散热风扇一般用多少转。 如果它恰好解决了您现在面临的问题&#xff0c;请不要忘记关注本站并立即开始&#xff01; 文章目录列表&#xff1a;大家一般机箱散热风扇都用多少转&#xff1f; 机箱散热风扇选择…

攻防世界[EASYHOOK]

攻防世界 * 2 题目&#xff1a;EASYHOOK题目地址&#xff1a;[](https://adworld.xctf.org.cn/challenges/list)总结&#xff1a;最后来聊一下hook 题目&#xff1a;EASYHOOK 题目地址&#xff1a; 拿到程序后无壳直接ida32打开&#xff0c;发现逻辑如下&#xff0c;输入长度…

【工具】cassetteai — 制作音乐就像现在写提示一样简单

Cassette 是一种人工智能驱动的音乐创作工具,使各种技能水平的用户都可以根据自己的特定需求和偏好生成高质量、免版税的音乐曲目。它基于基于潜在扩散 (LDM) 的机器学习模型,可以使用用户提供的文本描述来想象节拍。它具有易于使用的界面,用户可以输入各种参数,例如所需的…

Python工具-清理Unity(批量深度)清理U3D项目工程保留关键工程文件

前沿 1. Unity工程越来越多&#xff0c;很久不用的工程里存在了很多无用的大文件夹&#xff0c;极大的影响电脑容量。 2. 我电脑里面U3D工程只有17个&#xff0c;但容量就高达60GB&#xff0c;使用自己编写的工具清理后&#xff0c;减到了30GB多。清理了不是很重要的文件和文件…

基于DA优化CNN-LSTM的负荷预测

今天给大家分享DA优化CNN-LSTM的负荷预测&#xff0c;主要从算法原理和代码实战展开。需要了解更多算法代码的&#xff0c;可以点击文章左下角的阅读全文&#xff0c;进行获取哦~需要了解智能算法、机器学习、深度学习和信号处理相关理论的可以后台私信哦&#xff0c;下一期分享…

基于springboot+vue的电影院购票系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

docker将本地镜像pull到阿里云和registry

目录 一、上次到阿里云服务器 1、制作一个带有vim功能的Ubuntu镜像 2、在阿里云上面创建镜像仓库 3、从阿里云仓库中上传和拉取镜像 二、上传镜像到本地私有库registry 1、下载镜像docker registry 2、运行私有库registry&#xff0c;相当于本地有个私有docker hub。 3…

Unity:2D

目录 1. 简介 2. 2D Sorting 3. 9-slicing Sprites 3.1 9-slicing and Colliders 4. Sprite Renderer 5. Sprite Creator 6. Sprite Editor 6.1 Slice 6.1 Resize polygons 6.2 Custom Outline 6.3 Custom Physics Shape 6.4 Secondary Textures 6.5 Data Provider…

Nginx 全局块配置 user 指令详解

1. 前言 user 指令用于配置运行 nginx 服务器的 worker 进程的用户和用户组&#xff0c;这样对于系统权限的访问控制更加精细和安全 如果你修改过 nginx.conf&#xff0c;那么就会看到文件第一行的 user 指令配置&#xff0c;默认是被注释掉的&#xff08;默认使用 nobody 用户…

《边缘计算:连接未来的智慧之桥》

随着物联网、5G等技术的快速发展&#xff0c;边缘计算作为一种新兴的计算模式&#xff0c;正逐渐引起人们的广泛关注。边缘计算通过将数据处理和存储功能放置在距离数据产生源头更近的位置&#xff0c;实现了更快速、更可靠的数据处理和交换&#xff0c;为各行各业带来了前所未…

镁光的sdram手册阅读--MT48LCC16M16A2

镁光的sdram手册阅读–MT48LCC16M16A2 一、这个sdram的总容量是256Mb&#xff0c;MT48LC16M16A2对应的参数是&#xff1a;4Meg 16 4banks&#xff0c;也可表示为16M16。4164256Mbit。 1&#xff09;其中&#xff0c;4Meg表示单个bank包含的存储单元个数&#xff0c;计算公式…

架构整洁之道-读书总结

1 概述 1.1 关于本书 《架构整洁之道》&#xff08;Clean Architecture: A Craftsman’s Guide to Software Structure and Design&#xff09;是由著名的软件工程师Robert C. Martin&#xff08;又称为Uncle Bob&#xff09;所著。这本书提供了软件开发和架构设计的指导原则…

查看文件信息:ls,pwd,操作文件:cd,touch,mkdir,rmdir,rm,cp,mv

目录 ls 选项 -l -a 隐藏文件存在的意义 -F -d -R pwd cd 选项 ​编辑 touch 选项 mkdir 选项 -p rmdir 选项 -p rm 选项 cp 选项 -r -R (和-r的区别) mv 移动目录 改名 选项 rm改为mv ls 显示当前目录下的文件 选项 (可以合并使用,有的也可以写…

linux centos 安装jenkins,并构建spring boot项目

首先安装jenkins&#xff0c;使用war包安装&#xff0c;比较简单&#xff0c;注意看下载的版本需要的JDK版本&#xff0c;官网下载https://www.jenkins.io/download/ 把下载好的war包放到服务器上&#xff0c;然后运行&#xff0c;注意8080端口的放行 # 前台运行并指定端口 ja…