JUC之AQS必知必会,这样说就够了...
2020/2/22 17:02:57
本文主要是介绍JUC之AQS必知必会,这样说就够了...,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
AQS是JDK并发工具包下的一个模板类,作为并发包下的工具工具基础实现,我们经常使用的ReentrantLock,CountDownLatch,CyclicBarrier等都是基于它实现的,并且通过它我们可以很容易的实现自己的同步机制。
作为JUC中这么重要的一个类,有些东西还是要掌握的。
主要内容:
- AQS原理
- 如何利用AQS编写自己的同步机制
- 基于AQS的重入锁和Synchronized有什么区别
- 从AQS源码中你学到了什么
AQS原理
JDK源码要说原理,首先要提到其内部数据结构。其内部有两个子类:
- ConditionObject : 提供Java代码实现的Object.wait,notify,notifyAll等方法,并且支持多次wait,可以看做是Object这些方法的增强版。其内部也维护了一个队列,加上AQS的队列,总共有两个队列
- Node:AQS内部主要通过维护一个双向链表来存储参与同步机制的线程状态。双向链表基于Node节点来构建,每一个Node代表一个线程
- waitStatus: Node节点的一个熟悉,用于标记当前线程的等待状态。
- CANCELLED:即1,代表当前线程已经被取消了
- SIGNAL: -1,代表当前的线程等待被唤醒,即unparking
- CONDITION: -2,代表当前线程在条件队列上等待
- PROPAGATE:-3,当前线程节点的后续节点的acquireShare方法能够被无条件执行
- waitStatus: Node节点的一个熟悉,用于标记当前线程的等待状态。
另外AQS内部有一个state属性,AQS内部没有直接去操作state的地方,但是留给了我们三个方法去操作它。主要用于标记同步器的状态
- getState
- setState
- compareAndSetState
![image-20200221093528341](/upload/202002/22/202002221702574538.png)
AQS的队列操作
- head执行队列的头部
- tail执行队列的尾部
- 队列由Node组成,Node能获取其代表的Thread
![img](/upload/202002/22/202002221702576062.png)
AQS的Condition内部队列
![image-20200221092800481](/upload/202002/22/202002221702576540.png)
简述
能提到几个点,我觉得就OK了:
- 双向队列
- Node的waitStatus,大致那些
- state操作
利用AQS编写自己同步机制
根据上面提到的原理,想要使用AQS这个类:
1 编写一个新类
2 重写AQS的模板方法
- tryAcquire 尝试获取独占锁,
- tryRelease 尝试释放排它锁
- tryAcquireShared 尝试获取共享锁,返回负数代表失败,返回0代表当前的锁获取成功,但是后续无法获取,返回正数,代表后续的节点仍然可以继续获取
- tryReleaseShared 尝试释放共享锁
- isHeldExclusively 是否排它状态
3 利用AQS提供的基础方法补全模板方法,tryXXX开头的方法内容,已重入锁ReentrantLock为例,比较清晰。
protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); // c = 0代表没有线程修改过状态,那么尝试设置同步器的state。如果设置成功标记当前线程持有锁 if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } // 如果当前的线程持有锁。state + 1 // 否则返回false,代表无法获取 else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } 复制代码
4 调用AQS提供的方法来使用,三个维度:是否可中断、是否共享、是否超时
- acquire
- acquireInterruptibly
- acquireShared
- acquireSharedInterruptibly
- tryAcquireNanos
- tryAcquireSharedNanos
- release
- releaseShared
关于AQS几个Acquire方法的区别:www.jianshu.com/p/c48793646…
简单来说就是要知道try开头的方法是要我们自己实现的。能提到try开头的方法即可,最好了解AQS内部的方法大致有哪些
ReentrantLock和Synchronized区别
常规区别:
- ReentrantLock更加灵活,提供了超时获取锁,可中断锁。提供了非公平锁和非公平锁,而synchronized仅仅是非公平锁。
- 用法上,ReentrantLock必须手动释放锁,并且只能修饰代码块。而synchronized不用手动释放锁,除此之外可以修饰方法。
再问一句,ReentrantLock提供的不同获取锁的方式,比如超时获取,可中断获取,在AQS上的体现是什么呢?
即上面说的利用的是AQS的acquire,acquireInterruptibly,tryAcquireNanos。
至于是否公平的判断则是根据当前线程前是否仍有节点在等待。
学习感受
了解了AQS的关键点之后,代码并不是很复杂,主要知识点:维护双向链表,更新链表节点的状态,Lock.park,线程中断。
如果自己以后写模板类,AQS是一个很好的参照品。
其余也没太多想说的了,源码不是很复杂,所以没有贴源码出来
这篇关于JUC之AQS必知必会,这样说就够了...的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-07-06有没有什么开源的py项目可以对图像进行分类-icode9专业技术文章分享
- 2024-07-05feign默认connecttimeout和readtimeout是多少-icode9专业技术文章分享
- 2024-07-05idea控制台,日志太多,导致部分想看得日志被刷走 搜不到-icode9专业技术文章分享
- 2024-07-05The server selected protocol version Tls10 is not accepted by client preferences [TLs12]-icode9专业技术文章分享
- 2024-07-05怎么清理项目缓存-icode9专业技术文章分享
- 2024-07-04安装 Eyoucms详细图文教程-icode9专业技术文章分享
- 2024-07-04ueditor 复制文章时,图片的链接是一个下载图片地址,该如何处理?-icode9专业技术文章分享
- 2024-07-04怎样判断host有没有对wordpress有缓存呢-icode9专业技术文章分享
- 2024-07-04具有编译功能的系统make后,无法ssh连接-icode9专业技术文章分享
- 2024-07-04make后如何升级ssh-icode9专业技术文章分享