前言

本文简要介绍AQS以及其中两个重要概念:stateNode

AQS

抽象队列同步器AQSjava.util.concurrent.locks包下比较核心的类之一,包括AbstractQueuedSynchronizerAbstractQueuedLongSynchronizer两个类,两者分别采用intlong来定义同步状态state

AQSJava中一些常用锁容器的父类,提供了一套模板方法供子类自定义实现,主要职责在于:

  • 同步状态state的维护
  • 等待队列Node维护阻塞线程

同步状态state

state表示同步状态,不同子类使用它来表示不同含义,举例而言:

  • ReentranLock使用state表示持有锁的线程重入次数。当state大于0时,说明锁已被占用,则当前线程添加到等待队列
  • CountDownLatch使用state表示门栓计数。当计数大于0时,线程添加到等待队列;当线程等于0时,唤醒队列中线程
  • Semaphore使用state表示可用的信号量。当state等于0时,表示没有可用的信号量,线程添加到等待队列;线程执行完后,释放信号量,即state+1

通过三个不可重写方法操作state,子类可使用这三个方法:

// volatile 保证线程可见
private volatile int state; protected final int getState() {
return state;
} // 用于初始化场景
protected final void setState(int newState) {
state = newState;
} // 用于并发修改
protected final boolean compareAndSetState(int expect, int update) {
// unsafe#cas to update state
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

等待队列Node

AQS通过内置的FIFO队列来存储阻塞线程,队列本质是一个双向链表,初始时headtail都为null,当获取锁失败线程入队时才初始化辅助头节点(懒加载),将headtail都指向它,辅助头节点不存储线程,节点入队通过CASUnsafe实现,1.9开始varHandle取代了Unsafe)保证线程安全。

队列结构图:

抢占和共享模式

通过stateNodeAQS支持了独占和共享两种获取锁模式,子类只需要重写相关的方法就可以实现以独占或共享的方式获取锁。

// 尝试以独占模式获取操作,需要子类实现允许以独占模式获取它
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();
}

子类不需要实现上面所有方法,实现独占或者共享配套的方法即可。独占锁和共享锁举例如下:

独占锁:

  • ReentranLock
  • ReentranWriteReadLock.WriteLock

共享锁:

  • CountDownLatch
  • CyclicBarrier
  • Semaphore
  • ReentranWriteReadLock.ReadLock

独占锁和共享锁如何实现的呢?请看 Java并发之AQS原理解读(二)

Java并发之AQS原理解读(一)的更多相关文章

  1. Java并发之AQS原理解读(三)

    上一篇:Java并发之AQS原理解读(二) 前言 本文从源码角度分析AQS共享锁工作原理,并介绍下使用共享锁的子类如何工作的. 共享锁工作原理 共享锁与独占锁的不同之处在于,获取锁和释放锁成功后,都会 ...

  2. Java并发之AQS原理解读(二)

    上一篇: Java并发之AQS原理解读(一) 前言 本文从源码角度分析AQS独占锁工作原理,并介绍ReentranLock如何应用. 独占锁工作原理 独占锁即每次只有一个线程可以获得同一个锁资源. 获 ...

  3. Java并发之AQS原理剖析

    概述: AbstractQueuedSynchronizer,可以称为抽象队列同步器. AQS有独占模式和共享模式两种: 独占模式: 公平锁: 非公平锁: 共享模式: 数据结构: 基本属性: /** ...

  4. 并发之AQS原理(一) 原理介绍简单使用

    并发之AQS原理(一) 如果说每一个同步的工具各有各的强大,那么这个强大背后是一个相同的动力,它就是AQS. AQS是什么 AQS是指java.util.concurrent.locks包里的Abst ...

  5. 并发之AQS原理(三) 如何保证并发

    并发之AQS原理(三) 如何保证并发 1. 如何保证并发 AbstractQueuedSynchronizer 维护了一个state(代表了共享资源)和一个FIFO线程等待队列(多线程竞争资源被阻塞时 ...

  6. 并发之AQS原理(二) CLH队列与Node解析

    并发之AQS原理(二) CLH队列与Node解析 1.CLH队列与Node节点 就像通常医院看病排队一样,医生一次能看的病人数量有限,那么超出医生看病速度之外的病人就要排队. 一条队列是队列中每一个人 ...

  7. Java并发之AQS详解

    一.概述 谈到并发,不得不谈ReentrantLock:而谈到ReentrantLock,不得不谈AbstractQueuedSynchronizer(AQS)! 类如其名,抽象的队列式的同步器,AQ ...

  8. Java并发之AQS详解(转)

    一.概述 谈到并发,不得不谈ReentrantLock:而谈到ReentrantLock,不得不谈AbstractQueuedSynchronized(AQS)! 类如其名,抽象的队列式的同步器,AQ ...

  9. 【转】Java并发的AQS原理详解

    申明:此篇文章转载自:https://juejin.im/post/5c11d6376fb9a049e82b6253写的真的很棒,感谢老钱的分享. 打通 Java 任督二脉 —— 并发数据结构的基石 ...

随机推荐

  1. [考试总结]noip模拟22

    又发现模拟 \(22\) 的总结也咕掉了,现在补上它... 似乎又是gg的一场. 以为自己的部分分数打的很全,然而到后面发现自己的树剖打假了 \(\color{green}{\huge{\text{树 ...

  2. vscode配置java+gradle开发环境

    1.安装扩展包Java Extension Pack,里面包含java开发所必须的扩展 2.安装java jdk,8版本就是1.8版本,根据需要安装不同的版本 3.下载gradle,将bin文件夹添加 ...

  3. ajax 提交序列化表单

    1.提交序列化表单+参数: var a = $.param({'address':address,'delivity':delivity,'payment':payment}) + '&' + ...

  4. 云服务器是什么?ECS、BCC、CVM...

    什么是云服务器?云服务器有哪些优势?能用来干什么? 很多人不太了解云服务器的定义和用途. 云服务器是一种简单高效.处理能力可弹性伸缩的计算服务,帮助用户快速构建更稳定.安全的应用,提升运维效率,降低 ...

  5. 白话JavaScript原型链和继承

    原型基础 每个函数都有一个prototype属性,指向函数的原型对象 每个对象都一个私有属性 __proto__, 默认指向其构造函数的prototype 在JS中所有函数都是Function构造出来 ...

  6. Sth about Educational DP Contest

    Contest Website : atcoder.jp/contests/dp \[\begin{array}{c|C|c|c} TaskNum & TaskName & Statu ...

  7. SpringBoot - 根据目录结构自动生成路由前缀

    目录 前言 具体实现 配置文件指定基础包 自动补全路由前缀处理类 自动补全路由前缀配置类 测试类 测试 前言 本文介绍如何根据目录结构给RequestMapping添加路由前缀(覆盖RequestMa ...

  8. C运算符(算数运算符)

    运算符是一种告诉编译器执行特定的数学或逻辑操作的符号.C 语言内置了丰富的运算符,并提供了以下类型的运算符: 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 杂项运算符 1 //实列 2 3 ...

  9. Windows安装Hyper-V并优化部署Linux虚拟机

    安装Hyper-V 打开服务器管理器-->添加角色和功能-->下一步,选择Hyper-V,如图所示 然后一直默认往下走,一直到安装完成,然后重新启动计算机,如图所示 其中涉及的虚拟交换机. ...

  10. FIFO 深度了解

    嘻哈第二篇,深度聊聊各种细节. 优化与跨时钟阈分析