深入分析同步工具类之AbstractQueuedSynchronizer
概览:
AQS(简称)依赖内部维护的一个FIFO(先进先出)队列,可以很好的实现阻塞、同步;volatile修饰的属性state,哪个线程先改变这个状态值,那么这个线程就获得了优先权,可以做任何事(当然这些事肯定是我们预先写好的需要执行的业务代码咯[坏笑]),而其他线程则会被挂起,直到之前的线程执行完才会轮到下一个。 类库中同步工具类(CountDownLatch[闭锁]、Semaphore[信号量])就是依靠内部维护一个类来更改这个state来实现其自身的特性(说到底还是执行某些线程、阻塞一些线程)
代码分析前:
节点Node几个关键的属性:
1、volatile Thread thread;当前节点代表的线程
2、volatile Node next;当前结点的后继节点
3、volatile Node prev;当前结点的前驱节点
4、volatile int waitStatus;当前结点的等待状态
1 CANCELLED(线程取消)
-1 SIGNAL(表示当前节点的后继节点需要运行)
-2 CONDITION(表示当前节点在等待condition,也就是在condition队列中)
-3 PROPAGATE (表示当前场景下后续的acquireShared能够得以执行)
0(表示当前节点在sync队列中,等待着获取锁)
代码分析:
//获取状态
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
//该方法由子类去实现(改变state的值)
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
//为snyc队列添加节点
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;
//CAS更新尾节点
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;//退出当前循环
}
//将当前线程挂起
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
//线程执行完后释放持有的状态
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 tryRelease(int arg) {
throw new UnsupportedOperationException();
}
//将头节点的后继节点的线程恢复,这样后继节点就可以继续执行之前的循环,获取状态。
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0); /*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}
参考:
http://ifeve.com/introduce-abstractqueuedsynchronizer/
http://www.jianshu.com/p/d8eeb31bee5c
深入分析同步工具类之AbstractQueuedSynchronizer的更多相关文章
- 深入分析同步工具类之CountDownLatch
概览: CountDownLatch又称闭锁,其作用是让一个或者多个线程挂起,直到其他的线程执行完后恢复挂起的线程,使其继续执行.内部维护着一个静态内部类Sync,该类继承AbstractQueued ...
- 并发是个什么鬼之同步工具类CountDownLatch
扯淡 写这篇文章,我先酝酿一下,实不相瞒,脱离底层太久了,更确切的情况是,真没曾认真研究过.就目前来说,很多框架包括工具类已经把实现封装的很深,你只需轻轻的调用一下API,便不费半点力气.以至于大家会 ...
- 《java并发编程实战》读书笔记4--基础构建模块,java中的同步容器类&并发容器类&同步工具类,消费者模式
上一章说道委托是创建线程安全类的一个最有效策略,只需让现有的线程安全的类管理所有的状态即可.那么这章便说的是怎么利用java平台类库的并发基础构建模块呢? 5.1 同步容器类 包括Vector和Has ...
- Java多线程同步工具类之CountDownLatch
在过去我们实现多线程同步的代码中,往往使用join().wait().notiyAll()等线程间通信的方式,随着JUC包的不断的完善,java为我们提供了丰富同步工具类,官方也鼓励我们使用工具类来实 ...
- AQS的子类在各个同步工具类中的使用情况
AQS AQS(AbstractQueuedSynchronizer)是 java.util.concurrent的基础.J.U.C中宣传的封装良好的同步工具类Semaphore.CountDownL ...
- 同步工具类—— CountDownLatch
本博客系列是学习并发编程过程中的记录总结.由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅. 并发编程系列博客传送门 CountDownLatch简介 CountDownLa ...
- Java核心知识点学习----线程同步工具类,CyclicBarrier学习
线程同步工具类,CyclicBarrier日常开发较少涉及,这里只举一个例子,以做备注.N个人一块出去玩,相约去两个地方,CyclicBarrier的主要作用是等待所有人都汇合了,才往下一站出发. 1 ...
- java 利用同步工具类控制线程
前言 参考来源:<java并发编程实战> 同步工具类:根据工具类的自身状态来协调线程的控制流.通过同步工具类,来协调线程之间的行为. 可见性:在多线程环境下,当某个属性被其他线程修改后,其 ...
- 【同步工具类】CountDownLatch
闭锁是一种同步工具类,可以延迟线程的进度直到其达到终止状态. 作用:相当于一扇门,在到达结束状态之前,这扇门一直是关闭的,并且没有任务线程能够通过,当到达结束状态时,这扇门会打开并允许所有的线程通过, ...
随机推荐
- ubuntu-10.10嵌入式开发环境搭建【转】
本文转载自:http://blog.csdn.net/zjhsucceed_329/article/details/8036781 版权声明:本文为博主原创文章,未经博主允许不得转载. ubuntu- ...
- Email-ext plugin
https://wiki.jenkins.io/display/JENKINS/Email-ext+plugin General This plugin extends Jenkins built i ...
- 【168】ENVI入门系列
参考:ENVI-IDL中国的博客 [ENVI入门系列]01.ENVI产品简介与入门 [ENVI入门系列]02.自定义坐标系(北京54.西安80.2000坐标系) [ENVI入门系列]03.基于自带定位 ...
- Chrome教程之NetWork面板分析网络请求
官方文档:https://developers.google.com/web/tools/chrome-devtools/network/ 最近打算写一写Chrome教程文档,不知道大家最感兴趣的是什 ...
- OpenGL 2D模式
// // left top 这里设置的默认是左上角 // void push_view2d(int left, int top, int width, int height) { //glPushA ...
- PHP的包依赖管理工具Composer简介
composer是一个基于项目的依赖管理器,负责将php项目的所依赖的包和库安装在项目的目录中,默认不会不会安装任何数据到全局.他用于取代之前pear工具 1 安装Composer curl -sS ...
- UVa 101 - The Blocks Problem STL
题目:给你n个方块,有四种操作: .move a onto b,把a和b上面的方块都放回原来位置,然后把a放到b上面: .move a over b,把a上面的放回原处,然后把a放在b所在的方块堆的上 ...
- [Qt Creator 快速入门] 第5章 应用程序主窗口
对于日常见到的应用程序而言,许多都是基于主窗口的,主窗口中包含了菜单栏.工具栏.状态栏和中心区域等.这一章会详细介绍主窗口的每一个部分,还会涉及资源管理.富文本处理.拖放操作和文档打印等相关内容.重点 ...
- ACM_下一个排列
The Next Permutation Time Limit: 2000/1000ms (Java/Others) Problem Description: For this problem, yo ...
- TCP流量控制与拥塞解决
滑动窗口 但要提高网络利用率: nagle算法 - 延迟 慢启动.拥塞避免 发送端主导cwnd init set ssthresh & cwnd = swnd loop : 网不阻塞 ...