AbstractQueuedSynchronizer源码阅读(1)(AQS JDK1.8)

2023-05-16

AbstractQueuedSynchronizer

  • 前言
  • AbstractQueuedSynchronizer(1)(JDK 1.8)
    • 用途
    • 主要源码分析
      • Node内部类
      • ConditionObject类
        • 重要方法
      • 主要的属性及方法
        • 主要属性
        • 重要方法
      • 主要要实现的方法


前言

最近在使用Java 并发包时遇到一些问题,感觉对于其还是不够了解,故开始着手阅读相关源码。

AbstractQueuedSynchronizer(1)(JDK 1.8)

用途

Provides a framework for implementing blocking locks and related
synchronizers (semaphores, events, etc) that rely on
first-in-first-out (FIFO) wait queues.

我的理解:Java并发包里提供的一个用于实现锁和一系列同步器的一个框架。

主要源码分析

本身是一个抽象类,并发包里锁和同步器的实现大都继承了它。

Node内部类

  • Node类是一个静态final的内部类,主要用于实现一个等待队列。
  • 有独占模式和共享模式两种。
  • 主要的属性如下,其中比较重要的就是这个waitStatus,值为如下时的含义:
    1. SIGNAL(-1): 在当前节点释放或被取消时,唤醒后继节点;
    2. CANCELLED(1): 该节点不会再被阻塞,会被移除等待队列;
    3. CONDITION(-2):该节点当前处于一个条件等待队列里(应该给lock的Condition有关);
    4. PROPAGATE(-3):用于共享模式,暂时不清楚;
    5. 0:正常在队列中,如果是实现非公平锁,应该会拥有竞争锁的权利;
  • next和nextWaiter的区别,主要就是nextWaiter用于表示下一个处于wait condition队列的节点或共享模式的节点,next表示同步队列中下一个可以唤醒的节点;
volatile int waitStatus;

volatile Node prev;

volatile Node next;

volatile Thread thread;

Node nextWaiter;

ps: 如果处于独占模式下,该等待队列应该会逻辑上维护有两种队列,一个是可以正常竞争锁(如果用于实现锁的话)以及释放唤醒的节点同步队列,一个是处于等待某种条件的节点队列。

ConditionObject类

主要用于实现前面说的处于等待某种条件的节点队列,实现了相关入队出队操作,同时实现了Condition接口,其接口如下:

public interface Condition {

    void await() throws InterruptedException;

    void awaitUninterruptibly();
    
    long awaitNanos(long nanosTimeout) throws InterruptedException;
    
    boolean await(long time, TimeUnit unit) throws InterruptedException;
    
    boolean awaitUntil(Date deadline) throws InterruptedException;

    void signal();
    
    void signalAll();
}

ps: 底层实现原子操作的,用到了unsafe包CAS操作。

重要方法

public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
  	// 添加到条件等待队列中
    Node node = addConditionWaiter();
  	// 释放锁
    int savedState = fullyRelease(node);
    int interruptMode = 0;
  	// 判断是否在同步队列即可以正常争抢锁的队列中
    while (!isOnSyncQueue(node)) {
        LockSupport.park(this);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) // clean up if cancelled
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}
public final void signal() {
  	// 判断当前锁是否被当前线程独占,如果不是则抛出IllegalMonitorStateException
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    Node first = firstWaiter;
    if (first != null)
        doSignal(first);
}
private void doSignal(Node first) {
    do {
      	// 条件等待队列中删除头结点
        if ( (firstWaiter = first.nextWaiter) == null)
            lastWaiter = null;
        first.nextWaiter = null;
    } while (!transferForSignal(first) &&	// 将该节点插入同步队列中
             (first = firstWaiter) != null);
}

主要的属性及方法

主要属性

private transient volatile Node head;

private transient volatile Node tail;

/**
 * The synchronization state.
 */
private volatile int state;	// 在锁实现里表示的是持有该锁的线程数

private static final Unsafe unsafe = Unsafe.getUnsafe();

重要方法

  1. acquire(int arg)
/**
 * 独占模式,
 * 先尝试获取锁,失败则入Condition wait队列中
 * 忽略Interrupt
 */
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
// 入队默认waitStatus是0
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;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    enq(node);
    return node;
}
// 入队后再次尝试获取锁
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;
            }
            // 获锁失败后判断是否应该进行阻塞 使用LockSupport.park(this);底层还是用的unsafe包
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        // 获锁失败后
        if (failed)
            cancelAcquire(node);
    }
}
  1. release(int arg)
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

主要要实现的方法

protected boolean tryAcquire(int arg) {
    throw new UnsupportedOperationException();
}

protected boolean tryRelease(int arg) {
  	throw new UnsupportedOperationException();
}

protected int tryAcquireShared(int arg) {
  	throw new UnsupportedOperationException();
}

protected boolean tryReleaseShared(int arg) {
  	throw new UnsupportedOperationException();
}

protected boolean isHeldExclusively() {
  	throw new UnsupportedOperationException();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AbstractQueuedSynchronizer源码阅读(1)(AQS JDK1.8) 的相关文章

  • CentOS8安装JDK1.8

    文章目录 linux服务器上安装JDK1 8参考文章 linux服务器上安装JDK1 8 起因是在CentOS8上执行jps命令时 xff0c 报错 xff1a root 64 localhost kafka 2 13 2 8 0 jps
  • jenkins报错jdk1.8/jre/lib/amd64/libawt_xawt.so

    环境 Ubuntu14 04 x64 jenkins 2 32 1 错误1 AWT is not properly configured on this server Perhaps you need to run your contain
  • MacBook安装jdk1.8方便快捷稳定的方法

    MacBook安装jdk方便快捷稳定的方法 最简单快捷的jdk1 8安装 先查看有没有安装jdk xff1a java version 这样就是没有安装 然后去官网下载 下载地址 xff1a https www java com zh CN
  • (linux)CentOS -yum 安装jdk1.8

    1 搜索jdk安装 xff1a yum search java grep jdk 2 安装jdk 1 8 xff1a yum install java 1 8 0 openjdk 查看是否安装成功 xff1a java version 3
  • Collections.sort和Arrays.sort在jdk1.6和jdk1.7中区别

    1 写这边文章的原因 xff1a 最近在线上产品环境发现了部分用户数据返回排序问题 xff08 和之前理想中的排序不太一样 xff09 xff0c 由于服务器是集群配置 xff0c 猜测肯定是某一台排序服务出了问题 xff08 之前工作中也
  • jdk1.8中HashMap的扩容,从新增第一个元素开始

    置灰部分在当前场景下不考虑 1 新增第一个元素 新增第一个元素总结 xff1a 先进行数组容量初始化 xff0c 初始大小为16 xff0c 扩容界限为12 xff0c 再找出数组对应位置 xff0c 将新增的值放入 2 继续新增元素 xf
  • TeaPearce/Conditional_Diffusion_MNIST 源码阅读

    文章目录 tqdm超参数预运算nn Module register buffer绘制动画ddpmforward U net噪声预测模型信息向量掩码向量conext mask上采样层的信息融合恢复阶段 总结后记 tqdm dataset sp
  • DiffusionDet源码阅读(1)

    本文仅仅适用于已经通读过全文的小伙伴 本文代码节选自 mmdet 中的 DiffusionDet 代码 xff0c 目前该代码还处于 Development 阶段 xff0c 所以我博客里写的代码和之后的稳定版本可能稍有不同 xff0c 不
  • Error running 'ApplicationRun': 'xxx\jdk1.8.0_191\jre' is not a valid JRE home

    Error running ApplicationRun xxx jdk1 8 0 191 jre is not a valid JRE home解决办法 春节刚过 xff0c 疫情肆虐 从没见过如此冷清的成都 xff0c 阴沉的天空 xf
  • 每日lodash源码阅读(一)——createMathOperation

    每日lodash源码阅读 xff08 一 xff09 createMathOperation 一 写在前面二 使用举例三 源码分析add jscreateMathOperation js 一 写在前面 createMathOperation
  • 【JDK1.8 新特性】Lambda表达式

    1 什么是Lambda表达式 xff1f Lambda 是一个匿名函数 xff0c 我们可以把 Lambda 表达式理解为是一段可以传递的代码 xff08 将代码像数据一样进行传递 xff09 使用它可以写出更简洁 更灵活的代码 作为一种更
  • MSCKF-vio源码阅读

    作为一个菜狗来说 xff0c 一开始弄明白kf ekf等滤波方法实属不易 xff0c 但是一旦理解原理之后再发散到基于滤波的状态估计方法 xff0c 学习起来就会事半功倍 xff0c 就像导航包中的robot pose ekf xff0c
  • 一文就懂AQS!

    文章目录 AQS介绍AQS概念AQS模式分类AQS核心思想 AQS源码结构CLH同步队列state同步状态独占式同步状态获取与释放流程图总结 xff1a 共享式同步状态获取与释放 看了很多帖子 xff0c 原理说啥的都有 xff0c 算了还
  • HashMap在JDK1.7和1.8中的实现

    一 初窥HashMap HashMap是应用更广泛的哈希表实现 xff0c 而且大部分情况下 xff0c 都能在常数时间性能的情况下进行put和get操作 要掌握HashMap xff0c 主要从如下几点来把握 xff1a jdk1 7中底
  • 【FreeRTOS源码阅读】<2> task.c (1) 任务创建以及TCB、List的结构

    上篇讲述了list c关于链表操作的源码阅读 xff0c 此片文章将开始阅读task c task h相关结构体 由eTaskGetState返回的任务状态 typedef enum eRunning 61 0 一个任务查询自己的状态 xf
  • 源码阅读——validate-npm-package-name

    文章目录 前言一 源码阅读工具二 阅读源码1 目录结构2 package json3 index js 三 使用该包1 vue cli中使用2 create react app 中使用 总结 前言 validate npm package
  • Hive源码阅读--SQL的语法解析和语义分析--Driver

    前面五个类 xff0c 殊途同归都是CliDriver类 xff0c 他负责接受用户在命令行上输入的信息 xff0c 然后准备执行并将执行的结果返回 而真正底层干事情的是Driver xff0c 他将接受到的命令编译 xff0c 优化为MR
  • Caffe 源码(二) —— common 文件

    caffe 源码 common hpp cpp 文章目录 caffe 源码 common hpp cpp 1 宏定义 2 全局初始化函数 3 Caffe 类 单例模式 rng hpp 这里主要是对 caffe 框架源码进行梳理与学习 主要是
  • java AbstractOwnableSynchronizer与AbstractQueuedSynchronizer简析

    简介 AbstractQueuedSynchronizer全限定名java util concurrent locks AbstractQueuedSynchronizer 继承自java util concurrent locks Abs
  • JDK源码阅读之AbstractStringBuilder类

    AbstractStringBuilder类源码阅读 AbstractStringBuilder类的作用 AbstractStringBuilder类的类图 AbstractStringBuilder类的重点方法 属性变量 构造方法 精华方

随机推荐

  • android 五大布局(转)

    大家好 我们这一节讲一下Android对用五大布局对象 它们分别是FrameLayout 框架布局 不知道是不是这么翻译的 LinearLayout 线性布局 AbsoluteLayout 绝对布局 RelativeLayout 相对布局
  • flex校验

    package cn newtouch flexDemo business validator import mx binding utils BindingUtils import mx containers FormItem impor
  • docker--最全的网络类型(7类)

    目录 1bridge桥接模式 xff08 默认 xff09 2 host 3 overlay 4 ipvlan 5 macvlan 6 none 7 container 官网有六类 xff1a Networking overview Doc
  • flex 国际化

    Flex 开发 xff08 国际化 xff09 在Flex4 之前默认只支持en US ja JP 这两种本地化 xff0c 因此如果想在Flex 中支持中文或者其他语言时 xff0c 需要额外的操作 xff1a 1 首先添加新的本地化支持
  • 使用mysqladmin命令来修改mysql的root密码

    一般mysql的root默认密码为空 xff0c 如果你之前并没有设置过root密码就使用mysqladmin命令 xff0c 你可以使用如下mysqladmin命令来修改root密码 1 2 3 mysqladmin u root p p
  • CCF化学方程式的配平

    include lt iostream gt include lt string gt include lt cctype gt include lt unordered map gt using namespace std unorder
  • CCF 201909-4 推荐系统

    include lt cstdio gt include lt set gt include lt unordered map gt include lt algorithm gt using namespace std typedef l
  • CCF 201903-4 消息传递接口

  • Docker学习笔记(一)

    Docker学习笔记 xff08 一 xff09 什么是Docker Docker 使用 Google 公司推出的 Go 语言 进行开发实现 xff0c 基于 Linux 内核的 cgroup xff0c namespace xff0c 以
  • Docker学习笔记(二)

    Docker镜像 Docker 镜像是一个特殊的文件系统 xff0c 除了提供容器运行时所需的程序 库 资源 配置等文件外 xff0c 还包含了一些为运行时准备的一些配置参数 xff08 如匿名卷 环境变量 用户等 xff09 Docker
  • Java多线程里共享变量线程安全问题的原因

    Java多线程里共享变量线程安全问题的原因 Java多线程里对于共享变量的操作往往需要考虑进行一定的同步互斥操作 xff0c 原来是因为Java内存模型导致的共享内存对于线程不可见 Java 内存模型规定 xff0c 将所有的变量都存放在主
  • 重构-改善既有代码的设计读书笔记一

    重构 定义 为何重构 改进软件设计 使软件更容易理解 帮助找到Bug提高编程速度 何时重构 添加功能修改错误复审 总而言之 xff0c 当你觉得代码的可读性 可维护性 可修改性到达一定难以接受的程度 xff0c 就可以开始考虑是否可以使用重
  • Spring文档学习笔记一

    Spring文档学习笔记一 目录 Spring文档学习笔记一 Spring的宗旨 主要特征 几个核心理念 IoC 依赖解析过程 Spring循环依赖的解决方式 更详细的得估计得看Spring源码 1 4 2 Dependencies and
  • python数据结构算法DAY2| 快速排序

    目录 快速排序 xff08 quick sort xff09 1 什么是快速排序 2 快速排序思路 3 快速排序代码 4快速排序复杂度 5 快速排序函数与冒泡排序的效率比较 6 快速排序的缺点 解决办法 xff1a 快速排序 xff08 q
  • Go里w http.ResponseWriter,调用w.Write()方法报错

    Go里w http ResponseWriter写入报错http request method or response status code does not allow 1 下面是报错截图 2 点进去Write方法 它首先是一个接口 x
  • CCF 202012-3 带配额的文件系统 练习

    大模拟 xff0c 没涉及什么算法主要是数据结构的设计 细节的考虑 xff0c 挺锻炼的 xff0c 记录一下 xff0c 代码加了注释 include lt iostream gt include lt string gt include
  • 多接口继承和多层抽象类设计理解

    多接口继承和多层抽象类设计理解 以JDK集合List框架为例有感 以后可能又会有新的理解 xff0c 先记录一下 设计得好的接口一般也要遵循单一职责原则 xff0c 最上层的接口一般属于独立的 xff0c 不再有依赖的 xff0c 如Ite
  • 202012-5 星际旅行 (线段树模板60分)记录一下

    include lt bits stdc 43 43 h gt using namespace std typedef long long ll const int maxn 61 1e5 43 5 const ll MOD 61 1e9
  • 联机象棋(1)

    联机象棋 xff08 1 xff09 需求架构与开发技术主要设计与实现1 棋盘 棋子布局2 选棋 下棋3 人人对战匹配4 判断是否被将5 通信模块6 其他如声音效果等提升用户体验7 人机对战 尚未实现 8 最终实现效果图 需求 登录 注册
  • AbstractQueuedSynchronizer源码阅读(1)(AQS JDK1.8)

    AbstractQueuedSynchronizer 前言AbstractQueuedSynchronizer xff08 1 xff09 JDK 1 8 用途主要源码分析Node内部类ConditionObject类重要方法 主要的属性及