前言

本文简要介绍AQS以及其中两个重要概念:state和Node。

AQS

抽象队列同步器AQS是java.util.concurrent.locks包下比较核心的类之一,包括AbstractQueuedSynchronizer和AbstractQueuedLongSynchronizer两个类,两者分别采用int和long来定义同步状态state。

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

  • 同步状态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队列来存储阻塞线程,队列本质是一个双向链表,初始时head和tail都为null,当获取锁失败线程入队时才初始化辅助头节点(懒加载),将head和tail都指向它,辅助头节点不存储线程,节点入队通过CAS(Unsafe实现,1.9开始varHandle取代了Unsafe)保证线程安全。

队列结构图:

抢占和共享模式

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

// 尝试以独占模式获取操作,需要子类实现允许以独占模式获取它
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. Nginx负载均衡反向代理服务器

    1.第一步先在IIS中创建多个网站,分别用不同的端口号.这里创建两个网站端口号分别8084.8085,在Nginx配置中会用到.测试两个网站能正常访问. 2.配置Nginx 1)增加负载均衡请求列表 ...

  2. weex打包android apk采坑之旅(windows)

    1. npm install weex-toolkit -g 后weex命令不起作用 ,解决办法把weex.cmd所在的目录添加到环境变量PATH 2.weex命令每次报找不到文件'C:\Progra ...

  3. Python实用案例,Python脚本,Python实现批量加水印

    往期回顾 Python实现自动监测Github项目并打开网页 Python实现文件自动归类 Python实现帮你选择双色球号码 Python实现每日更换"必应图片"为"桌 ...

  4. Spring Boot中使用时序数据库InfluxDB

    除了最常用的关系数据库和缓存之外,之前我们已经介绍了在Spring Boot中如何配置和使用MongoDB.LDAP这些存储的案例.接下来,我们继续介绍另一种特殊的数据库:时序数据库InfluxDB在 ...

  5. Resnet网络详细结构(针对Cifar10)

    Resnet网络详细结构(针对Cifar10) 结构 具体结构(Pytorch) conv1 (conv1): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, ...

  6. LeetCode入门指南 之 排序

    912. 排序数组 给你一个整数数组 nums,请你将该数组升序排列. 归并排序 public class Sort { //归并排序 public static int[] MergeSort(in ...

  7. [TensorFlow2.0]-正则化

    本人人工智能初学者,现在在学习TensorFlow2.0,对一些学习内容做一下笔记.笔记中,有些内容理解可能较为肤浅.有偏差等,各位在阅读时如有发现问题,请评论或者邮箱(右侧边栏有邮箱地址)提醒. 若 ...

  8. JavaScript学习03(函数)

    函数 函数定义 JavaScript 函数是通过 function 关键词定义的. 声明定义 function functionName(parameters) { 要执行的代码 } 被声明的函数不会 ...

  9. 结合scipy.linalg在Python中使用线性系统

    摘要:将线性代数概念应用到实际问题中scipy.linalg 使用 Python 和 NumPy处理向量和矩阵 使用线性系统模拟实际问题 使用求解线性系统 scipy.linalg 本文分享自华为云社 ...

  10. 对象池在 .NET (Core)中的应用[1]: 编程体验

    借助于有效的自动化垃圾回收机制,.NET让开发人员不在关心对象的生命周期,但实际上很多性能问题都来源于GC.并不说.NET的GC有什么问题,而是对象生命周期的跟踪和管理本身是需要成本的,不论交给应用还 ...