Java并发框架——公平性
所谓公平性指所有线程对临界资源申请访问权限的成功率都一样,不会让某些线程拥有优先权。通过前面的CLH Node FIFO学习知道了等待队列是一个先进先出的队列,那么是否就可以说每条线程获取锁时就是公平的呢?关于公平性这里分拆成三个点分别阐述:
① 准备入队列的节点,此情况讨论的是线程加入等待队列时产生的竞争是否公平,线程在尝试获取锁失败后将被加入等待队列,这时多个线程通过自旋将节点加入队列,所有线程在自旋过程中是无法保证其公平性的,可能后来的线程比早到的先进入队列,所以节点入队列不具公平性。
② 等待队列中的节点,情况①中成功加入队列后即成为等待队列中的节点,我们知道此队列是一个先入先出队列,那么很简单能得到,队列中的所有节点是公平的,他们都按照顺序等待自己被前驱节点唤醒并获取锁,所以等待队列中的节点具有公平性。
③ 闯入的节点,这种情况是指一个新线程到达共享资源边界时不管等待队列中是否存在其他等待节点它都将优先尝试去获取锁,这种称为可闯入策略。可闯入特性破坏了公平性,AQS框架对外体现的公平性主要由此体现,下面将对闯入特性展开分析。
AQS提供的基础获取锁算法是一种可闯入的算法,即如果有新线程到来先进行一次获取尝试,不成功的情况下才将当前线程加入等待队列。如图2-5-9-6所示,等待队列中节点线程按照顺序一个接一个尝试去获取共享资源的使用权,某时刻头结点线程准备尝试获取的同时另外一条线程闯入,此线程并非直接加入等待队列的尾部,而是先跟头结点线程竞争获取资源,闯入线程如果成功获取共享资源则直接执行,头结点线程则继续等待下一次尝试,如此一来闯入线程成功插队,后来的线程比早到的线程先执行,说明AQS基础获取算法是不严格公平的。
图2-5-9-6 闯入线程
基础获取算法逻辑简化如下:首先尝试获取锁,假如获取失败才创建节点并加入到等待队列的尾部,接着通过不断循环检查是否轮到自己执行,当然此过程为了提高性能可能将线程先挂起,最终由前驱节点唤醒。
if(尝试获取锁失败) {
创建node
使用CAS方式把node插入到队列尾部
while(true){
if(尝试获取锁成功 并且 node的前驱节点为头节点){
把当前节点设置为头节点
跳出循环
}else{
使用CAS方式修改node前驱节点的waitStatus标识为signal
if(修改成功)
挂起当前线程
}
}
为什么要使用闯入策略?可闯入的策略通常可以提供更高的总吞吐量。由于一般同步器颗粒度比较小,也可以说共享资源的范围较小,而线程从阻塞状态到被唤醒所消耗的时间周期可能是通过共享资源时间周期的几倍甚至几十倍,如此一来线程唤醒过程中将存在一个很大的时间周期空窗期,导致资源没有得到充分利用,为了提高吞吐量,引入这种闯入策略,它可以使在等待队列头结点从阻塞到被唤醒的时间段内闯入的线程直接获取锁并通过同步器,以便充分利用唤醒过程这一空窗期,大大增加了吞吐率。另外,闯入机制的实现对外提供一种竞争调节机制,即开发者可以在自定义同步器中定义闯入尝试获取的次数,假设次数为n则不断重复获取直到n次都获取不成功才把线程加入等待队列中,随着次数n的增加可以增大成功闯入的几率。同时,这种闯入策略可能导致等待队列中的线程饥饿,因为锁可能一直被闯入的线程获取,但由于一般持有同步器的时间很短暂而避免饥饿的发生,反之如果保护的代码体很长并且持有同步器的时间较长,这将大大增加等待队列无限等待的风险。
在实际情况中还是要根据用户需求制定策略,在一个公平性要求很高的场景,则可以把闯入策略去除掉以达到公平。在自定义同步器中可以通过AQS预留方法tryAcquire方法实现,只需判断当前线程是否为等待队列中头结点对应的线程,若不是则直接返回false,尝试获取失败。但前面这种公平性是相对Java语法语义层面上的公平性,在现实中JVM的实现会直接影响线程执行的顺序。
喜欢研究java的同学可以交个朋友,下面是本人的微信号:
Java并发框架——公平性的更多相关文章
- Java并发框架AbstractQueuedSynchronizer(AQS)
1.前言 本文介绍一下Java并发框架AQS,这是大神Doug Lea在JDK5的时候设计的一个抽象类,主要用于并发方面,功能强大.在新增的并发包中,很多工具类都能看到这个的影子,比如:CountDo ...
- Java 并发系列之十:java 并发框架(2个)
1. Fork/Join框架 2. Executor框架 3. ThreadPoolExecutor 4. ScheduledThreadPoolExecutor 5. FutureTask 6. t ...
- 深入理解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) 深入 ...
- 深入理解Java并发框架AQS系列(三):独占锁(Exclusive Lock)
一.前言 优秀的源码就在那里 经过了前面两章的铺垫,终于要切入正题了,本章也是整个AQS的核心之一 从本章开始,我们要精读AQS源码,在欣赏它的同时也要学会质疑它.当然本文不会带着大家逐行过源码(会有 ...
- Java并发框架——AQS中断的支持
线程的定义给我们提供了并发执行多个任务的方式,大多数情况下我们会让每个任务都自行执行结束,这样能保证事务的一致性,但是有时我们希望在任务执行中取消任务,使线程停止.在java中要让线程安全.快速.可靠 ...
- Java并发框架——什么是AQS框架
什么是AQS框架 1995年sun公司发布了第一个java语言版本,可以说从jdk1.1到jdk1.4期间java的使用主要是在移动应用和中小型企业应用中,在此类领域中基本不用设计大型并发场景,当然也 ...
- Java并发框架——AQS之如何使用AQS构建同步器
AQS的设计思想是通过继承的方式提供一个模板让大家可以很容易根据不同场景实现一个富有个性化的同步器.同步器的核心是要管理一个共享状态,通过对状态的控制即可以实现不同的锁机制.AQS的设计必须考虑把复杂 ...
随机推荐
- 【USACO12JAN】视频游戏的连击Video Game Combos
题目描述 Bessie is playing a video game! In the game, the three letters 'A', 'B', and 'C' are the only v ...
- [bzoj4161]Shlw loves matrix I
来自FallDream的博客,未经允许,请勿转载,谢谢. 给定数列 {hn}前k项,其后每一项满足 hn = a1*h(n-1) + a2*h(n-2) + ... + ak*h(n-k) 其中 a1 ...
- HttpServletRequest获取URL?后面的内容
获取URL?后面的内容 如https://i.cnblogs.com/EditPosts.aspx?opt=1 String para = request.getQueryString(): para ...
- SQL语句删除字段,改变字段长度
1.改变字段长度 ALTER TABLE T_MSG_SEND_R_ACC MODIFY reply_content VARCHAR(512); 2.删除字段ALTER TABLE MSG_TX_BA ...
- maven generating project in batch mode hang
最新版已经自己就设置了 设置maven不要从远程服务器上获取catalog,增加参数-DarchetypeCatalog=internal 如何在idea里设置maven参数:
- js页面刷新跳转的几种方式及区别
跳转常用方法: window.location.href="index.php"; window.history.back(-1);//类似于按钮,参数是负几,就后退几次. win ...
- 单页应用动态设置页面title
1.适用场景:所有通过router路由的单页应用. 2.示例代码:本文以vue-router为例. 在router.js中: let router = new Router({ routes: [ { ...
- scratch写的图灵机
大多数人对于scratch不感冒,因为觉得这是孩子玩的.的确,积木的方式不适合专业程序员写代码,然而别小看scratch,怎么说,它也是图灵完备的.而且,过程支持递归,虽然带不了返回值. 虽然计算速度 ...
- JavaScript Date(日期)对象
返回当日的日期和时间 如何使用 Date() 方法获得当日的日期. getFullYear() 使用 getFullYear() 获取年份. getTime() getTime() 返回从 1970 ...
- 实验与作业(Python)-03 Python程序实例解析
截止日期: 要求: 下周实验课前上交,做好后在实验课上检查可获取平时分. 做出进阶或选做的的请用清晰的标致标识出来,方便老师批改 本次作业:可提交也可不提交.作业算平时成绩. 本次作业内容量较大,请组 ...