对AQS进行解析后,先来实现两个简单的基于AQS的类,然后再解析juc里基于AQS构造的类。

1、基于AQS的类的示例

首先先看这个类,这个类是《Java并发编程实战》的一个示例,AQS源码的注释里也给了类似的实现。这个类是以共享模式实现的,在调用signal之前,调用await方法的线程都将被阻塞,main方法的示例演示了这种情况。

  1. 1 public class Latch {
  2. 2 private Sync sync = new Sync();
  3. 3
  4. 4 private class Sync extends AbstractQueuedSynchronizer{
  5. 5 @Override
  6. 6 protected int tryAcquireShared(int arg) {//重写tryAcquireShared方法
  7. 7 return getState() == 1 ? 1 : -1;
  8. 8 }
  9. 9
  10. 10 @Override
  11. 11 protected boolean tryReleaseShared(int arg) {//重写tryReleaseShared方法
  12. 12 setState(1);
  13. 13 return true;
  14. 14 }
  15. 15 }
  16. 16
  17. 17 public void signal(){//调用这个方法会调用releaseShared方法,会调用tryReleaseShared方法,将state设置为0 没调用这个方法之前调用tryAcquireShared的返回值都是0,线程会阻塞
  18. 18 sync.releaseShared(0);
  19. 19 }
  20. 20
  21. 21 public void await() throws InterruptedException {//调用这个方法会调用acquireSharedInterruptibly方法,会调用tryAcquireShared方法,如果返回值大于0,则集训运行;否则阻塞
  22. 22 sync.acquireSharedInterruptibly(0);
  23. 23 }
  24. 24
  25. 25 public static void main(String [] args) throws InterruptedException {
  26. 26 Latch latch = new Latch();
  27. 27 Runnable runnable = new Runnable() {
  28. 28 @Override
  29. 29 public void run() {
  30. 30 try {
  31. 31 latch.await();
  32. 32 } catch (InterruptedException e) {
  33. 33 e.printStackTrace();
  34. 34 }
  35. 35 System.out.println("haha");
  36. 36 }
  37. 37 };
  38. 38
  39. 39 new Thread(runnable).start();
  40. 40 new Thread(runnable).start();
  41. 41
  42. 42 Thread.sleep(5 * 1000);
  43. 43
  44. 44 System.out.println("xixi");
  45. 45 latch.signal();
  46. 46 }
  47. 47 }

这个类是AQS注释里给出的一个实现的一部分。这个类是以独占模式实现的。同时只能有一个线程

  1. 1 public class Mock {
  2. 2 private Sync sync = new Sync();
  3. 3
  4. 4 private class Sync extends AbstractQueuedSynchronizer{
  5. 5 @Override
  6. 6 protected boolean isHeldExclusively() {
  7. 7 return getState() == 1;
  8. 8 }
  9. 9
  10. 10 @Override
  11. 11 protected boolean tryAcquire(int acquires) {//重写tryAcquire方法,用cas尝试将state从0置为1
  12. 12 assert acquires == 1;
  13. 13 if (compareAndSetState(0, 1)){
  14. 14 setExclusiveOwnerThread(Thread.currentThread());//如果将state从0置为1成功,则将当前线程设置为独占模式持有资源的线程
  15. 15 return true;
  16. 16 }
  17. 17 return false;
  18. 18 }
  19. 19
  20. 20 @Override
  21. 21 protected boolean tryRelease(int releases) {
  22. 22 assert releases == 1;
  23. 23 if (getState() == 0){//如果state为0,则说明资源没有被占用,不需要释放 抛出一个异常
  24. 24 throw new IllegalMonitorStateException();
  25. 25 }
  26. 26 setExclusiveOwnerThread(null);//将资源拥有者线程置为null
  27. 27 setState(0);//将state置为0,资源释放
  28. 28 return true;
  29. 29 }
  30. 30 }
  31. 31
  32. 32 @Test
  33. 33 public void lock(){
  34. 34 sync.acquire(1);
  35. 35 }
  36. 36
  37. 37 public boolean tryAcquire(){
  38. 38 return sync.tryAcquire(1);
  39. 39 }
  40. 40
  41. 41 public void unlock(){
  42. 42 sync.release(1);
  43. 43 }
  44. 44
  45. 45 public static void main(String [] args) throws InterruptedException {
  46. 46 Mock mock = new Mock();
  47. 47 Runnable runnable = new Runnable() {
  48. 48 @Override
  49. 49 public void run() {
  50. 50 mock.lock();
  51. 51 System.out.println("haha");
  52. 52 try {
  53. 53 Thread.sleep(5 * 1000);
  54. 54 } catch (InterruptedException e) {
  55. 55 e.printStackTrace();
  56. 56 }
  57. 57 mock.unlock();
  58. 58 }
  59. 59 };
  60. 60
  61. 61 new Thread(runnable).start();
  62. 62 new Thread(runnable).start();
  63. 63
  64. 64 mock.lock();
  65. 65 System.out.println("xixi");
  66. 66 Thread.sleep(5 * 1000);
  67. 67 mock.unlock();
  68. 68 }
  69. 69 }

2、juc里基于AQS构造的类

Semaphore类:

内部抽象类Sync:

  1. 1 abstract static class Sync extends AbstractQueuedSynchronizer {
  2. 2 private static final long serialVersionUID = 1192457210091910933L;
  3. 3
  4. 4 Sync(int permits) {
  5. 5 setState(permits);
  6. 6 }
  7. 7
  8. 8 final int getPermits() {
  9. 9 return getState();
  10. 10 }
  11. 11
  12. 12 final int nonfairTryAcquireShared(int acquires) {//不公平尝试获取共享锁
  13. 13 for (;;) {
  14. 14 int available = getState();
  15. 15 int remaining = available - acquires;
  16. 16 if (remaining < 0 ||
  17. 17 compareAndSetState(available, remaining))//如果剩下的资源不够分配,直接返回,会进入阻塞状态;如果剩下的资源足够分配,自旋直到分配成功,返回分配后剩下的资源
  18. 18 return remaining;
  19. 19 }
  20. 20 }
  21. 21
  22. 22 protected final boolean tryReleaseShared(int releases) {//尝试释放锁
  23. 23 for (;;) {//自旋
  24. 24 int current = getState();
  25. 25 int next = current + releases;
  26. 26 if (next < current)//next溢出为负数 抛出异常
  27. 27 throw new Error("Maximum permit count exceeded");
  28. 28 if (compareAndSetState(current, next))//cas修改state
  29. 29 return true;
  30. 30 }
  31. 31 }
  32. 32
  33. 33 final void reducePermits(int reductions) {//减少许可
  34. 34 for (;;) {
  35. 35 int current = getState();
  36. 36 int next = current - reductions;
  37. 37 if (next > current) // underflow
  38. 38 throw new Error("Permit count underflow");
  39. 39 if (compareAndSetState(current, next))
  40. 40 return;
  41. 41 }
  42. 42 }
  43. 43
  44. 44 final int drainPermits() {//将许可清空
  45. 45 for (;;) {
  46. 46 int current = getState();
  47. 47 if (current == 0 || compareAndSetState(current, 0))
  48. 48 return current;
  49. 49 }
  50. 50 }
  51. 51 }

内部类NonfairSync:

这个类继承自抽象类Sync,实现了tryAcquireShared方法,由类名可知这个类是非公平获取资源的(非公平就是说一个线程尝试获取资源时,就算有其它线程在排队获取资源,但是由于这些资源处于等待状态,会让新的线程先尝试获取资源,如果直接能获取就让新线程直接运行,不再进入等待队列排队;如果不能直接获取,就再进入阻塞队列。非公平可能减少线程阻塞唤醒的次数,性能要比公平好一些)。

在AQS里的acquireShared方法会先调用tryAcquireShared方法再根据结果决定是执行还是等待,这里tryAcquireShared的实现就可以让Semaphore有非公平的功能。

  1. 1 static final class NonfairSync extends Sync {
  2. 2 private static final long serialVersionUID = -2694183684443567898L;
  3. 3
  4. 4 NonfairSync(int permits) {
  5. 5 super(permits);
  6. 6 }
  7. 7
  8. 8 protected int tryAcquireShared(int acquires) {
  9. 9 return nonfairTryAcquireShared(acquires);
  10. 10 }
  11. 11 }

内部类FairSync:

上面说了非公平的版本,公平的版本和非公平的版本区别就在tryAcquireShared方法里面。在FairSync里,如果队列里有其它线程等待,就直接返回-1,新线程会直接放入队列中;如果没有其它线程等待才尝试获取资源。

  1. 1 static final class FairSync extends Sync {
  2. 2 private static final long serialVersionUID = 2014338818796000944L;
  3. 3
  4. 4 FairSync(int permits) {
  5. 5 super(permits);
  6. 6 }
  7. 7
  8. 8 protected int tryAcquireShared(int acquires) {
  9. 9 for (;;) {
  10. 10 if (hasQueuedPredecessors())
  11. 11 return -1;
  12. 12 int available = getState();
  13. 13 int remaining = available - acquires;
  14. 14 if (remaining < 0 ||
  15. 15 compareAndSetState(available, remaining))
  16. 16 return remaining;
  17. 17 }
  18. 18 }
  19. 19 }

Semaphore的构造函数:

Semaphore的构造函数有两个,都需要传许可(资源)数,另一个可以传是否公平,来决定资源分配的方式。

  1. 1 public Semaphore(int permits) {
  2. 2 sync = new NonfairSync(permits);
  3. 3 }
  4. 4
  5. 5 public Semaphore(int permits, boolean fair) {
  6. 6 sync = fair ? new FairSync(permits) : new NonfairSync(permits);
  7. 7 }

Semaphore的其它方法基本上都是调用Sync(AQS)的方法实现的,可以看AQS的解析或Semaphore抽象内部类Sync的解析。

CountDownLatch类:

CountDownLatch类中文翻译为闭锁,它的工作机制是设定一个初值,在初值减为0之前调用await方法会使当前线程进入等待状态,调用countDown减到0时会将其它等待的线程唤醒。和Semaphore类似,它的功能也主要由继承AQS构建Sync实现。

内部类Sync:

  1. 1 private static final class Sync extends AbstractQueuedSynchronizer {
  2. 2 private static final long serialVersionUID = 4982264981922014374L;
  3. 3
  4. 4 Sync(int count) {
  5. 5 setState(count);
  6. 6 }
  7. 7
  8. 8 int getCount() {
  9. 9 return getState();
  10. 10 }
  11. 11
  12. 12 protected int tryAcquireShared(int acquires) {//如果state减到1,返回都为正;如果没有减到1,返回都为负
  13. 13 return (getState() == 0) ? 1 : -1;
  14. 14 }
  15. 15
  16. 16 protected boolean tryReleaseShared(int releases) {
  17. 17 // Decrement count; signal when transition to zero
  18. 18 for (;;) {
  19. 19 int c = getState();
  20. 20 if (c == 0)
  21. 21 return false;
  22. 22 int nextc = c-1;//nextc是c-1
  23. 23 if (compareAndSetState(c, nextc))//每次调用都将state减去一
  24. 24 return nextc == 0;
  25. 25 }
  26. 26 }
  27. 27 }

await方法:

sync调用acquireSharedInterruptibly方法会调用上面实现的tryAcquireShared,如果state没减到0就返回负,线程等待进入队列。

  1. 1 public void await() throws InterruptedException {
  2. 2 sync.acquireSharedInterruptibly(1);
  3. 3 }

countDown方法:

sync调用releaseShared方法会调用上面实现的tryReleaseShared,然后会调用AQS的doReleaseShared唤醒队首的线程,队首的线程获取资源时会唤醒后面线程(因为此时调用tryAcquireShared返回值一直为正),后面线程唤醒再后面线程,直至全部唤醒。

  1. 1 public void countDown() {
  2. 2 sync.releaseShared(1);
  3. 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. Windows Server 2008 R2系统安装

    把系统U盘插到服务器上,然后启动服务器进入BIOS界面选择U盘启动. 根据服务器的不同,进入BIOS界面的按钮也不一样,主流的有F10.F11.F12.F2.ESC.delete等. 在从BIOS启动 ...

  2. Soul API 网关源码解析 03

    目标 使用 soul 代理 dubbo 服务 dubbo 服务如何注册到网关的? dubbo 插件是如何工作的? 理清 http --> 网关--> dubbo provider 整条链路 ...

  3. cc 攻击

    糟糕,系统又被攻击了 原创 二马读书 二马读书 10月16日 几年前,我们的电商平台遭遇过一次CC攻击(一种分布式网络攻击,后面有详细介绍

  4. (Sqlserver)sql求连续问题

    题目一:create table etltable( name varchar(20) , seq int, money int); create table etltarget ( name var ...

  5. super 多重继承 super() function with multilevel inheritance

    Python | super() function with multilevel inheritance - GeeksforGeeks https://www.geeksforgeeks.org/ ...

  6. Java NIO ———— Buffer 缓冲区详解 入门

    引言缓冲区是一个用于特定基本类型的容器.由java.nio 包定义,所有缓冲区都是 Buffer 抽象类的子类. Java NIO 中的 Buffer ,主要用于与NIO 通道进行交互.数据从通道存入 ...

  7. 利用Mixins扩展类功能

    8.18 利用Mixins扩展类功能 - python3-cookbook 3.0.0 文档 https://python3-cookbook.readthedocs.io/zh_CN/latest/ ...

  8. 四. Ribbon负载均衡服务调用

    1. 概述 1.1 Ribbon是什么 SpringCloud Ribbon是基于Netflix Ribbon实现的一套客户端,是负载均衡的工具. Ribbon是Netflix发布的开源项目,主要功能 ...

  9. Java 性能调优的 11 个实用技巧

    大多数开发人员认为性能优化是个比较复杂的问题,需要大量的经验和知识.是的,这并不没有错.诚然,优化应用程序以获得最好的性能并不是一件容易的事情,但这并不意味着你在没有获得这些经验和知识之前就不能做任何 ...

  10. 码一次前后台post请求交互,以及接口的使用,json数据格式的传递

    近几天,公司疯狂加班,然后补做了很多功能,很多东西虽然是自己熟悉的,但是却不会上手,动手实践能力仍需加强,对此对一些代码记录,留待学习和总结. 简单描述功能 具体实现 前台JSP.JS.后台actio ...