对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里的相关类的解析的更多相关文章

  1. react中关于create-react-app2里css相关配置

    先看 webpack.config.dev.js 里的相关代码: // style files regexes const cssRegex = /\.css$/; const cssModuleRe ...

  2. Java并发包——线程安全的Collection相关类

    Java并发包——线程安全的Collection相关类 摘要:本文主要学习了Java并发包下线程安全的Collection相关的类. 部分内容来自以下博客: https://www.cnblogs.c ...

  3. Java并发包——线程安全的Map相关类

    Java并发包——线程安全的Map相关类 摘要:本文主要学习了Java并发包下线程安全的Map相关的类. 部分内容来自以下博客: https://blog.csdn.net/bill_xiang_/a ...

  4. Android随笔之——Android时间、日期相关类和方法

    今天要讲的是Android里关于时间.日期相关类和方法.在Android中,跟时间.日期有关的类主要有Time.Calendar.Date三个类.而与日期格式化输出有关的DateFormat和Simp ...

  5. android 6.0 SDK中删除HttpClient的相关类的解决方法

    一.出现的情况 在eclipse或 android studio开发, 设置android SDK的编译版本为23时,且使用了httpClient相关类的库项目:如android-async-http ...

  6. Android 6.0删除Apache HttpClient相关类的解决方法

    相应的官方文档如下: 上面文档的大致意思是,在Android 6.0(API 23)中,Google已经移除了Apache HttpClient相关的类,推荐使用HttpUrlConnection. ...

  7. Java基础之Java常用类--Object类,字符串相关类,包装类,日期相关类,数字相关类

    Java是一种面向对象的语言,也就是将万事万物可以描述为对象,特点如下: 1.面向对象是常见的一种思考习惯,符合人们的思考习惯.2.面向对象的出现,将复杂的事情简单化.3.面向对象的出现,将之前过程中 ...

  8. 《转》深入理解Activity启动流程(二)–Activity启动相关类的类图

    本文原创作者:Cloud Chou. 出处:本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 在介绍Activity的详细启动流程之前,先为大家介绍Act ...

  9. 深入理解Activity启动流程(二)–Activity启动相关类的类图

    本文原创作者:Cloud Chou. 欢迎转载,请注明出处和本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 在介绍Activity的详细启动流程之前,先 ...

随机推荐

  1. 注解 @AutoConfigureBefore 和 @AutoConfigureAfter 的用途

    注解 @AutoConfigureBefore 和 @AutoConfigureAfter 的用途 介绍: 如果你想将在SpringBoot项目中的配置类进行排序,那么用到spring-boot-au ...

  2. uni-app开发经验分享八: 实现微信APP支付的全过程详解

    背景 最近项目使用uni-app实现微信支付,把过程简单记录下,帮助那些刚刚基础uni-app,苦于文档的同学们.整体来说实现过程和非uni-app的实现方式没有太大不同,难点就在于uni-app对于 ...

  3. 推荐大家去撸60元的阿里云ACA DevOps认证

    要试题的右边扫码支付10元,私聊博客哈,说出你微信号,留下邮箱,发你邮箱Pdf文件,这么便宜拿证!!

  4. 通过封装openpyxl模块实现自己的Excel操作类

    """ excel类封装需要提供以下功能: 1.选择表单功能 2.读取一个单元格的数据功能 3.读取一行数据功能 4.读取表单中所有数据功能 5.往单元格中写入数据功能 ...

  5. 【Soul源码探秘】插件链实现

    引言 插件是 Soul 的灵魂. Soul 使用了插件化设计思想,实现了插件的热插拔,且极易扩展.内置丰富的插件支持,鉴权,限流,熔断,防火墙等等. Soul 是如何实现插件化设计的呢? 一切还得从插 ...

  6. 纯手工撸一个vue框架

    前言 vue create 真的很方便,但是很多人欠缺的是手动撸一遍.有些人离开脚手架都不会开发了. Vue最简单的结构 步骤 搭建最基本的结构 打开空文件夹,通过 npm init 命令生成pack ...

  7. 支持 gRPC 长链接,深度解读 Nacos 2.0 架构设计及新模型

    支持 gRPC 长链接,深度解读 Nacos 2.0 架构设计及新模型 原创 杨翊(席翁) 阿里巴巴云原生 2020-12-28    

  8. JVM虚拟机垃圾回收(GC)算法及优缺点

    一.什么是GC   GC是jvm的垃圾回收,垃圾回收的规律和原则为:   次数上频繁收集新生区(Young)   次数上较少收集养老区(Old)   基本上不动永久区(Perm) 二.GC算法(分代收 ...

  9. (ETL)ETL架构师面试题(转载)

    1. What is a logical data mapping and what does it mean to the ETL team?什么是逻辑数据映射?它对ETL项目组的作用是什么? 答: ...

  10. 洛谷P6218

    感觉此题是P4317 花神的数论题的变形版 Description 求一段区间内二进制中 \(0\) 的个数不小于 \(1\) 的个数的数的个数 Solution 数位 DP 先考虑状态转移方程式,如 ...