Java并发框架——同步状态的管理
整个AQS框架核心功能都是围绕着其32位整型属性state进行,一般可以说它表示锁的数量,对同步状态的控制可以实现不同的同步工具,例如闭锁、信号量、栅栏等等。为了保证可见性此变量被声明为volatile,保证每次的原子更新都将及时反映到每条线程上。而对于同步状态的管理可以大体分为两块,一是独占模式的管理,另外是共享模式的管理。通过对这两种模式的灵活变换可以实现多种不同的同步器,如下图,对state的控制可以看成一个管道,管道的大小决定了同时通过的线程,独占模式好比宽度只容许一个线程通过的管道,在这种模式下线程只能逐一通过管道,任意时刻管内只能存在一条线程,这便形成了互斥效果。而共享模式就是管道宽度大于1的管道,可以同时让n条管道通过,吞吐量增加但可能存在共享数据一致性问题。(注意:两种模式的讨论忽略了队列的管理逻辑,实际上CLH
Node的引入是为了优化竞争带来的性能问题,不影响同步状态管理的探讨)
图2-5-9-5 独占模式与共享模式
如何通过state实现独占模式和共享模式?在此之前先了解AQS框架中相关的getState、setState、compareAndSetState三个操作state的基本方法,前两个方法是普通的获取设置方法,其必须保证不存在数据竞争的情况下使用,compareAndSetState方法则提供了CAS方式的硬件级别的原子更新。两种模式就是通过这些方法对state操作实现不同同步模式,下面给出最简单的实现。
独占模式
public boolean tryAcquire(int acquires) {
if (compareAndSetState(0, 1)) {
return true;
}
return false;
}
protected boolean tryRelease(int releases) {
setState(0);
return true;
}
多条线程通过tryAcquire尝试把state变量改为1,由于CAS算法的保证,最终有且仅有一条线程成功修改state,修改成功的线程代表获取锁成功,将拥有往下执行的权利,进入管道。当执行完毕退出管道时执行tryRelease尝试把state变量改为0,让出管道,此处由于不存在线程竞争所以可直接使用setState,接着其他未通过的线程继续重复尝试。
共享模式
public int tryAcquireShared(int interval) {
for (;;) {
int current = getState();
int newCount = current - 1;
if (newCount < 0 || compareAndSetState(current, newCount)) {
return newCount;
}
}
}
public boolean tryReleaseShared(int interval) {
for (;;) {
int current = getState();
int newCount = current + 1;
if (compareAndSetState(current, newCount)) {
return true;
}
}
}
与独占模式不同的是对state的管理及判断条件,独占模式state的值只能为0或1,而共享模式的state是可以被出事换成任意整数,一般初始值表示提供一个同时n条线程通过的管道宽度,这样一来,多条线程通过tryAcquireShared尝试将state的值减去1,成功修改state后就返回新值,只有当新值大于等于0才表示获取锁成功,拥有往下执行的权利,进入管道。在执行完毕时线程将调用tryReleaseShared尝试修改state值使之增加1,表示我已经执行完了并让出管道的通道供后面线程使用,需要说明的是与独占模式不同,由于可能存在多条线程并发释放锁,所以此处必须使用基于CAS算法的修改方法,修改成功后其他线程便可继续竞争锁。
ASQ框架提供了对同步状态state的基本操作,了解了两种模式对state操作开发者可能很自由地自定义自己的同步器。实际中AQS框架在提供state状态管理接口的同时也将维护等待队列的工作,两项工作被封装成一个模板,规定了工作流程,工作流程包括什么条件下加入等待队列、什么条件移除等待节点、如何操作等待队列、需不需要阻塞、支不支持中断等等,对外仅仅提供state状态操作接口供开发者自定义,而队列的维护工作已经绑定在模板中,无需你自己动手。
喜欢研究java的同学可以交个朋友,下面是本人的微信号:
Java并发框架——同步状态的管理的更多相关文章
- Java并发框架——AQS堵塞队列管理(一)——自旋锁
我们知道一个线程在尝试获取锁失败后将被堵塞并增加等待队列中,它是一个如何的队列?又是如何管理此队列?这节聊聊CHL Node FIFO队列. 在谈到CHL Node FIFO队列之前,我们先分析这样 ...
- Java并发框架——AQS阻塞队列管理(一)——自旋锁
我们知道一个线程在尝试获取锁失败后将被阻塞并加入等待队列中,它是一个怎样的队列?又是如何管理此队列?这节聊聊CHL Node FIFO队列. 在谈到CHL Node FIFO队列之前,我们先分析这种队 ...
- Java并发框架——AQS阻塞队列管理(三)——CLH锁改造
在CLH锁核心思想的影响下,Java并发包的基础框架AQS以CLH锁作为基础而设计,其中主要是考虑到CLH锁更容易实现取消与超时功能.比起原来的CLH锁已经做了很大的改造,主要从两方面进行了改造:节点 ...
- Java并发框架——AQS阻塞队列管理(二)——自旋锁优化
看Craig, Landin, and Hagersten发明的CLH锁如何优化同步带来的花销,其核心思想是:通过一定手段将所有线程对某一共享变量轮询竞争转化为一个线程队列且队列中的线程各自轮询自己的 ...
- Java 并发 线程同步
Java 并发 线程同步 @author ixenos 同步 1.异步线程本身包含了执行时需要的数据和方法,不需要外部提供的资源和方法,在执行时也不关心与其并发执行的其他线程的状态和行为 2.然而,大 ...
- Java并发框架AbstractQueuedSynchronizer(AQS)
1.前言 本文介绍一下Java并发框架AQS,这是大神Doug Lea在JDK5的时候设计的一个抽象类,主要用于并发方面,功能强大.在新增的并发包中,很多工具类都能看到这个的影子,比如:CountDo ...
- 深入理解Java并发框架AQS系列(一):线程
深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 一.概述 1.1.前言 重剑无锋,大巧不工 读j.u.c包下的源码,永远无法绕开的经典 ...
- 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念
深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 一.AQS框架简介 AQS诞生于Jdk1.5,在当时低效且功能单一的synchroni ...
- 深入理解Java并发框架AQS系列(四):共享锁(Shared Lock)
深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 深入理解Java并发框架AQS系列(三):独占锁(Exclusive Lock) 深入 ...
随机推荐
- ●POJ 3974 Palindrome(Manacher)
题链: http://poj.org/problem?id=3974 题解: Manacher 求最长回文串长度. 终于会了传说中的马拉车,激动.推荐一个很棒的博客:https://www.61mon ...
- Uva 437 巴比伦塔 && UVA10003
要求底面严格小于它下方立方体的长宽,求出最高情况,一块石头可以多次使用 用结构体记录一块石头的三种放置情况,按面积排序. dp[i] = max(dp[i],dp[j] + block[i].high ...
- POJ 3233 (矩阵)
题意:对于矩阵A,求A^1 + ...... + A^k 按照矩阵十大经典题的思路大致做了下. 在k为奇数时: A^( k / 2+1)+ 1) * (A^1 + ....... A^(k/2)) ...
- hdu 5532(最长上升子序列)
Input The first line contains an integer T indicating the total number of test cases. Each test case ...
- 使用PL/SQL Developer连接远程DB(本机不安装Oracle客户端)
本文内容亲测可行环境: 服务端:centos6.7 ,oracle 11g r2 ,动态注册,监听端口号:1521 用户端:win7 ,没有安装ORACLE及其客户端 准备文件:plsql ...
- 运行C++程序是出现错误:cannot open Debug/1.exe for writing
今天,打开VC6.0环境编了个小程序,谁知给我报了“cannot open Debug/1.exe for writing”这样一个错,然后,我就纳闷了,这是什么错丫? 想了半天,后想通,为什么会这样 ...
- Angular中 build的时候遇到的错误--There are multiple modules with names that only differ in casing
今天早上遇到一个Angular的编译的时候的错误 具体信息: There are multiple modules with names that only differ in casing.This ...
- 解决Spring Boot 使用RedisTemplate 存储键值出现乱码 \xac\xed\x00\x05t\x00
spring-data-redis的RedisTemplate<K, V>模板类在操作redis时默认使用JdkSerializationRedisSerializer来进行序列化解决方法 ...
- canvas初学 半动态画太极图
可直接复制粘贴运行 <!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head&g ...
- 反射获取 Class
原文链接:https://www.codemore.top/cates/Backend/post/2018-04-26/reflect-class 类 Java中每个类型要么是引用类型,要么是原生类型 ...