AbstractQueuedSynchronizer的使用和juc里的相关类的解析
对AQS进行解析后,先来实现两个简单的基于AQS的类,然后再解析juc里基于AQS构造的类。
1、基于AQS的类的示例
首先先看这个类,这个类是《Java并发编程实战》的一个示例,AQS源码的注释里也给了类似的实现。这个类是以共享模式实现的,在调用signal之前,调用await方法的线程都将被阻塞,main方法的示例演示了这种情况。
1 public class Latch {
2 private Sync sync = new Sync();
3
4 private class Sync extends AbstractQueuedSynchronizer{
5 @Override
6 protected int tryAcquireShared(int arg) {//重写tryAcquireShared方法
7 return getState() == 1 ? 1 : -1;
8 }
9
10 @Override
11 protected boolean tryReleaseShared(int arg) {//重写tryReleaseShared方法
12 setState(1);
13 return true;
14 }
15 }
16
17 public void signal(){//调用这个方法会调用releaseShared方法,会调用tryReleaseShared方法,将state设置为0 没调用这个方法之前调用tryAcquireShared的返回值都是0,线程会阻塞
18 sync.releaseShared(0);
19 }
20
21 public void await() throws InterruptedException {//调用这个方法会调用acquireSharedInterruptibly方法,会调用tryAcquireShared方法,如果返回值大于0,则集训运行;否则阻塞
22 sync.acquireSharedInterruptibly(0);
23 }
24
25 public static void main(String [] args) throws InterruptedException {
26 Latch latch = new Latch();
27 Runnable runnable = new Runnable() {
28 @Override
29 public void run() {
30 try {
31 latch.await();
32 } catch (InterruptedException e) {
33 e.printStackTrace();
34 }
35 System.out.println("haha");
36 }
37 };
38
39 new Thread(runnable).start();
40 new Thread(runnable).start();
41
42 Thread.sleep(5 * 1000);
43
44 System.out.println("xixi");
45 latch.signal();
46 }
47 }
这个类是AQS注释里给出的一个实现的一部分。这个类是以独占模式实现的。同时只能有一个线程
1 public class Mock {
2 private Sync sync = new Sync();
3
4 private class Sync extends AbstractQueuedSynchronizer{
5 @Override
6 protected boolean isHeldExclusively() {
7 return getState() == 1;
8 }
9
10 @Override
11 protected boolean tryAcquire(int acquires) {//重写tryAcquire方法,用cas尝试将state从0置为1
12 assert acquires == 1;
13 if (compareAndSetState(0, 1)){
14 setExclusiveOwnerThread(Thread.currentThread());//如果将state从0置为1成功,则将当前线程设置为独占模式持有资源的线程
15 return true;
16 }
17 return false;
18 }
19
20 @Override
21 protected boolean tryRelease(int releases) {
22 assert releases == 1;
23 if (getState() == 0){//如果state为0,则说明资源没有被占用,不需要释放 抛出一个异常
24 throw new IllegalMonitorStateException();
25 }
26 setExclusiveOwnerThread(null);//将资源拥有者线程置为null
27 setState(0);//将state置为0,资源释放
28 return true;
29 }
30 }
31
32 @Test
33 public void lock(){
34 sync.acquire(1);
35 }
36
37 public boolean tryAcquire(){
38 return sync.tryAcquire(1);
39 }
40
41 public void unlock(){
42 sync.release(1);
43 }
44
45 public static void main(String [] args) throws InterruptedException {
46 Mock mock = new Mock();
47 Runnable runnable = new Runnable() {
48 @Override
49 public void run() {
50 mock.lock();
51 System.out.println("haha");
52 try {
53 Thread.sleep(5 * 1000);
54 } catch (InterruptedException e) {
55 e.printStackTrace();
56 }
57 mock.unlock();
58 }
59 };
60
61 new Thread(runnable).start();
62 new Thread(runnable).start();
63
64 mock.lock();
65 System.out.println("xixi");
66 Thread.sleep(5 * 1000);
67 mock.unlock();
68 }
69 }
2、juc里基于AQS构造的类
Semaphore类:
内部抽象类Sync:
1 abstract static class Sync extends AbstractQueuedSynchronizer {
2 private static final long serialVersionUID = 1192457210091910933L;
3
4 Sync(int permits) {
5 setState(permits);
6 }
7
8 final int getPermits() {
9 return getState();
10 }
11
12 final int nonfairTryAcquireShared(int acquires) {//不公平尝试获取共享锁
13 for (;;) {
14 int available = getState();
15 int remaining = available - acquires;
16 if (remaining < 0 ||
17 compareAndSetState(available, remaining))//如果剩下的资源不够分配,直接返回,会进入阻塞状态;如果剩下的资源足够分配,自旋直到分配成功,返回分配后剩下的资源
18 return remaining;
19 }
20 }
21
22 protected final boolean tryReleaseShared(int releases) {//尝试释放锁
23 for (;;) {//自旋
24 int current = getState();
25 int next = current + releases;
26 if (next < current)//next溢出为负数 抛出异常
27 throw new Error("Maximum permit count exceeded");
28 if (compareAndSetState(current, next))//cas修改state
29 return true;
30 }
31 }
32
33 final void reducePermits(int reductions) {//减少许可
34 for (;;) {
35 int current = getState();
36 int next = current - reductions;
37 if (next > current) // underflow
38 throw new Error("Permit count underflow");
39 if (compareAndSetState(current, next))
40 return;
41 }
42 }
43
44 final int drainPermits() {//将许可清空
45 for (;;) {
46 int current = getState();
47 if (current == 0 || compareAndSetState(current, 0))
48 return current;
49 }
50 }
51 }
内部类NonfairSync:
这个类继承自抽象类Sync,实现了tryAcquireShared方法,由类名可知这个类是非公平获取资源的(非公平就是说一个线程尝试获取资源时,就算有其它线程在排队获取资源,但是由于这些资源处于等待状态,会让新的线程先尝试获取资源,如果直接能获取就让新线程直接运行,不再进入等待队列排队;如果不能直接获取,就再进入阻塞队列。非公平可能减少线程阻塞唤醒的次数,性能要比公平好一些)。
在AQS里的acquireShared方法会先调用tryAcquireShared方法再根据结果决定是执行还是等待,这里tryAcquireShared的实现就可以让Semaphore有非公平的功能。
1 static final class NonfairSync extends Sync {
2 private static final long serialVersionUID = -2694183684443567898L;
3
4 NonfairSync(int permits) {
5 super(permits);
6 }
7
8 protected int tryAcquireShared(int acquires) {
9 return nonfairTryAcquireShared(acquires);
10 }
11 }
内部类FairSync:
上面说了非公平的版本,公平的版本和非公平的版本区别就在tryAcquireShared方法里面。在FairSync里,如果队列里有其它线程等待,就直接返回-1,新线程会直接放入队列中;如果没有其它线程等待才尝试获取资源。
1 static final class FairSync extends Sync {
2 private static final long serialVersionUID = 2014338818796000944L;
3
4 FairSync(int permits) {
5 super(permits);
6 }
7
8 protected int tryAcquireShared(int acquires) {
9 for (;;) {
10 if (hasQueuedPredecessors())
11 return -1;
12 int available = getState();
13 int remaining = available - acquires;
14 if (remaining < 0 ||
15 compareAndSetState(available, remaining))
16 return remaining;
17 }
18 }
19 }
Semaphore的构造函数:
Semaphore的构造函数有两个,都需要传许可(资源)数,另一个可以传是否公平,来决定资源分配的方式。
1 public Semaphore(int permits) {
2 sync = new NonfairSync(permits);
3 }
4
5 public Semaphore(int permits, boolean fair) {
6 sync = fair ? new FairSync(permits) : new NonfairSync(permits);
7 }
Semaphore的其它方法基本上都是调用Sync(AQS)的方法实现的,可以看AQS的解析或Semaphore抽象内部类Sync的解析。
CountDownLatch类:
CountDownLatch类中文翻译为闭锁,它的工作机制是设定一个初值,在初值减为0之前调用await方法会使当前线程进入等待状态,调用countDown减到0时会将其它等待的线程唤醒。和Semaphore类似,它的功能也主要由继承AQS构建Sync实现。
内部类Sync:
1 private static final class Sync extends AbstractQueuedSynchronizer {
2 private static final long serialVersionUID = 4982264981922014374L;
3
4 Sync(int count) {
5 setState(count);
6 }
7
8 int getCount() {
9 return getState();
10 }
11
12 protected int tryAcquireShared(int acquires) {//如果state减到1,返回都为正;如果没有减到1,返回都为负
13 return (getState() == 0) ? 1 : -1;
14 }
15
16 protected boolean tryReleaseShared(int releases) {
17 // Decrement count; signal when transition to zero
18 for (;;) {
19 int c = getState();
20 if (c == 0)
21 return false;
22 int nextc = c-1;//nextc是c-1
23 if (compareAndSetState(c, nextc))//每次调用都将state减去一
24 return nextc == 0;
25 }
26 }
27 }
await方法:
sync调用acquireSharedInterruptibly方法会调用上面实现的tryAcquireShared,如果state没减到0就返回负,线程等待进入队列。
1 public void await() throws InterruptedException {
2 sync.acquireSharedInterruptibly(1);
3 }
countDown方法:
sync调用releaseShared方法会调用上面实现的tryReleaseShared,然后会调用AQS的doReleaseShared唤醒队首的线程,队首的线程获取资源时会唤醒后面线程(因为此时调用tryAcquireShared返回值一直为正),后面线程唤醒再后面线程,直至全部唤醒。
1 public void countDown() {
2 sync.releaseShared(1);
3 }
可重入锁的实现要复杂一点,另开一篇。
AbstractQueuedSynchronizer的使用和juc里的相关类的解析的更多相关文章
- react中关于create-react-app2里css相关配置
先看 webpack.config.dev.js 里的相关代码: // style files regexes const cssRegex = /\.css$/; const cssModuleRe ...
- Java并发包——线程安全的Collection相关类
Java并发包——线程安全的Collection相关类 摘要:本文主要学习了Java并发包下线程安全的Collection相关的类. 部分内容来自以下博客: https://www.cnblogs.c ...
- Java并发包——线程安全的Map相关类
Java并发包——线程安全的Map相关类 摘要:本文主要学习了Java并发包下线程安全的Map相关的类. 部分内容来自以下博客: https://blog.csdn.net/bill_xiang_/a ...
- Android随笔之——Android时间、日期相关类和方法
今天要讲的是Android里关于时间.日期相关类和方法.在Android中,跟时间.日期有关的类主要有Time.Calendar.Date三个类.而与日期格式化输出有关的DateFormat和Simp ...
- android 6.0 SDK中删除HttpClient的相关类的解决方法
一.出现的情况 在eclipse或 android studio开发, 设置android SDK的编译版本为23时,且使用了httpClient相关类的库项目:如android-async-http ...
- Android 6.0删除Apache HttpClient相关类的解决方法
相应的官方文档如下: 上面文档的大致意思是,在Android 6.0(API 23)中,Google已经移除了Apache HttpClient相关的类,推荐使用HttpUrlConnection. ...
- Java基础之Java常用类--Object类,字符串相关类,包装类,日期相关类,数字相关类
Java是一种面向对象的语言,也就是将万事万物可以描述为对象,特点如下: 1.面向对象是常见的一种思考习惯,符合人们的思考习惯.2.面向对象的出现,将复杂的事情简单化.3.面向对象的出现,将之前过程中 ...
- 《转》深入理解Activity启动流程(二)–Activity启动相关类的类图
本文原创作者:Cloud Chou. 出处:本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 在介绍Activity的详细启动流程之前,先为大家介绍Act ...
- 深入理解Activity启动流程(二)–Activity启动相关类的类图
本文原创作者:Cloud Chou. 欢迎转载,请注明出处和本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 在介绍Activity的详细启动流程之前,先 ...
随机推荐
- 图解 ECDHE 密钥交换算法
HTTPS 常用的密钥交换算法有两种,分别是 RSA 和 ECDHE 算法. 其中,RSA 是比较传统的密钥交换算法,它不具备前向安全的性质,因此现在很少服务器使用的.而 ECDHE 算法具有前向安全 ...
- OLED的波形曲线、进度条、图片显示(STM32 HAL库 模拟SPI通信 5线OLED屏幕)详细篇
少废话,先上效果图 屏幕显示效果 全家福 一.基础认识及引脚介绍 屏幕参数: 尺寸:0.96英寸 分辨率:128*64 驱动芯片:SSD1306 驱动接口协议:SPI 引脚说明: 二. ...
- OAuth2.0是干什么的?
OAuth2.0是干什么的? 首先用户有一些数据: 将数据存储在服务器上: 这时候有一个应用要访问数据: 如果这个应用是一个恶意程序呢?所以需要一个检验来判断请求是不是安全的: 如何判断是不是安全的? ...
- Bitter.Core系列七:Bitter ORM NETCORE ORM 全网最粗暴简单易用高性能的 NETCore ORM 示例 更新删除插入
Bitter Orm 在操作数据库增删改的时候,支持模型驱动和直接执行裸SQL 操作,示例代码如下: 一:模型驱动(增删改) /// <summary> /// 插入,删除,更新示例(模型 ...
- 解析MySQL中存储时间日期类型的选择问题
解析MySQL中存储时间日期类型的选择问题_Mysql_脚本之家 https://www.jb51.net/article/125715.htm 一般应用中,我们用timestamp,datetime ...
- ACID 原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)。
https://en.wikipedia.org/wiki/ACID https://zh.wikipedia.org/wiki/ACID //ACID compliant , row-level l ...
- functools.singledispatchmethod(Python 3.8) | 码农网 https://www.codercto.com/a/83245.html
functools.singledispatchmethod(Python 3.8) | 码农网 https://www.codercto.com/a/83245.html
- Hyper-v安装centos后的网络配置
修改配置文件 进入目录:cd /etc/sysconfig/network-scripts/ 修改ifcfg-eth0文件(不通机器文件名可能不同,可以通过 ip addr 命令查看网卡名) HWAD ...
- CF1428C
Description 有一个只包含'A'与'B'的字符串,每次可以消掉一个 "AB" 或一个 "BB",并把剩下的拼在一起,求字符串最短的长度. 题意已经够简 ...
- k8s之集群管理
导读 经过前面k8s系列的文章,这一系列已经基本完成,现在就用几篇文章说一下日常的集群维护. 目录 更新资源对象的Label Namespace:集群环境共享与隔离 部署集群监控 部署Web UI管理 ...