AQS的设计思想是通过继承的方式提供一个模板让大家能够非常easy依据不同场景实现一个富有个性化的同步器。同步器的核心是要管理一个共享状态,通过对状态的控制即能够实现不同的锁机制。

AQS的设计必须考虑把复杂反复且easy出错的队列管理工作统一抽象出来管理,而且要统一控制好流程,而暴露给子类调用的方法主要就是操作共享状态的方法,以此提供对状态的原子性操作。一般子类的同步器中使用AQS提供的getState、setState、compareAndSetState三个方法,前两个为普通的get和set方法,要使用这两个方法必需要保证不存在数据竞争,compareAndSetState方法提供了CAS方式的硬件级别的原子更新。

对于独占模式而言。锁获取与释放的流程的定义则交给acquire和release两个方法,它们定义了锁获取与释放的逻辑。同一时候也是提供给子类获取和释放锁的接口。它的运行逻辑能够參考前面的“锁的获取与释放”。它提供了一个如何强大的模板?由以下的伪代码能够清晰展示出来。请注意tryAcquire和tryRelease这两个方法,它就是留给子类实现个性化的方法,通过这两个方法对共享状态的管理能够自己定义多种多样的同步器。而队列的管理及流程的控制则不是你需要考虑的问题。
① 锁获取模板
if(tryAcquire(arg)) {
    创建node
    使用CAS方式把node插入到队列尾部
    while(true){
    if(tryAcquire(arg) 而且 node的前驱节点为头节点){
把当前节点设置为头节点
    跳出循环
}else{
    使用CAS方式改动node前驱节点的waitStatus标识为signal
    if(改动成功)
        挂起当前线程 
}
}
② 锁释放模板
    if(tryRelease(arg)){
唤醒兴许节点包括的线程
}

我们能够觉得同步器可实现不论什么不同锁的语义。一般提供给使用者的锁是用AQS框架封装实现的更高层次的实现,提供一种更加形象的API让使用者使用起来更加方便简洁。而不是让使用者直接接触AQS框架,比如。ReentrantLock、Semphore、CountDownLatch等等。这些不同的形象的锁让你使用起来更好理解更加得心应手,并且不easy混淆。

然而这些锁都是由AQS实现。AQS同步器面向的是线程和状态的控制,定义了线程获取状态的机制及线程排队等操作,非常好地隔离了两者的关注点,高层关注的是场景的使用,而AQS同步器则关心的是并发的控制。

假如你要实现一个自己定义同步装置,官方推荐的做法是将集成AQS同步器的子类作为同步装置的内部类,而同步装置中相关的操作仅仅需代理成子类中相应的方法就可以。往下用一个简单的样例看看怎样实现自己的锁,因为同步器被分为两种模式。独占模式和共享模式。所以样例也相应给出。

① 独占模式。独占模式採取的样例是银行服务窗体,假如某个银行网点仅仅有一个服务窗体,那么此银行服务窗体仅仅能同一时候服务一个人。其它人必须排队等待,所以这样的银行窗体同步装置是一个独占模型。

第一个类是银行窗体同步装置类。它依照推荐的做法使用一个继承AQS同步器的子类实现,并作为子类出现。第二个类是測试类,形象一点地说。有三位良民到银行去办理业务,各自是tom、jim和jay,我们使用BankServiceWindow就能够约束他们排队,一个一个轮着办理业务而避免陷入混乱的局面。
public class BankServiceWindow {
private final Sync sync;
public BankServiceWindow() {
sync = new Sync();
}
private static class Sync extends AbstractQueuedSynchronizer {
public boolean tryAcquire(int acquires) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
protected boolean tryRelease(int releases) {
if (getState() == 0)
throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
}
public void handle() {
sync.acquire(1);
}
public void unhandle() {
sync.release(1);
}
}

public class BankServiceWindowTest {
   public static void main(String[] args){
   final BankServiceWindow bankServiceWindow=new BankServiceWindow();
   Thread tom=new Thread(){
   public void run(){
   bankServiceWindow.handle();
   System.out.println("tom開始办理业务");
   try {
   this.sleep(5000);
   } catch (InterruptedException e) {
   e.printStackTrace();
   }
   System.out.println("tom结束办理业务");
   bankServiceWindow.unhandle();
   }
   };
   Thread jim=new Thread(){
   public void run(){
   bankServiceWindow.handle();
   System.out.println("jim開始办理业务");
   try {
   this.sleep(5000);
   } catch (InterruptedException e) {
   e.printStackTrace();
   }
   System.out.println("jim结束办理业务");
   bankServiceWindow.unhandle();
   }
   };
   Thread jay=new Thread(){
   public void run(){
   bankServiceWindow.handle();
   System.out.println("jay開始办理业务");
   try {
   this.sleep(5000);
   } catch (InterruptedException e) {
   e.printStackTrace();
   }
   System.out.println("jay结束办理业务");
   bankServiceWindow.unhandle();
   }
   };
   tom.start();
   jim.start();
   jay.start();
    }
}
输出结果例如以下:
tom開始办理业务
tom结束办理业务
jim開始办理业务
jim结束办理业务
jay開始办理业务
jay结束办理业务
明显tom、jim、jay仨是排队完毕的。可是无法保证三者的顺序,可能是tom、jim、jay,也可能是tom、jay、jim。由于在入列曾经的运行先后是无法确定的,它的语义是保证一个接一个办理。

假设没有同步器限制的情况。输出结果将不可预測。可能为输出例如以下:
jim開始办理业务
jay開始办理业务
tom開始办理业务
jay结束办理业务
jim结束办理业务
tom结束办理业务

② 共享模式,共享模式採取的样例相同是银行服务窗体,随着此网点的发展。办理业务的人越来越多,一个服务窗体已经无法满足需求,于是又分配了一位员工开了另外一个服务窗体,这时就能够同一时候服务两个人了,但两个窗体都有人占用时相同也必须排队等待,这样的服务窗体同步器装置就是一个共享型。第一个类是共享模式的同步装置类,跟独占模式不同的是它的状态的初始值能够自由定义,获取与释放就是对状态递减和累加操作。第二个类是測试类,tom、jim和jay再次来到银行,一个有两个窗体甚是高兴,他们能够两个人同一时候办理了,时间缩减了不少。
public class BankServiceWindows {
private final Sync sync;
public BankServiceWindows(int count) {
sync = new Sync(count);
}
private static class Sync extends AbstractQueuedSynchronizer {
Sync(int count) {
setState(count);
}
public int tryAcquireShared(int interval) {
for (;;) {
int current = getState();
int newCount = current - 1;
if (newCount < 0 || compareAndSetState(current, newCount)) {
return newCount;
}
}
}
public boolean tryReleaseShared(int interval) {
for (;;) {
int current = getState();
int newCount = current + 1;
if (compareAndSetState(current, newCount)) {
return true;
}
}
}
}

public void handle() {
sync.acquireShared(1);
}

public void unhandle() {
sync.releaseShared(1);
}

}

public class BankServiceWindowsTest {
public static void main(String[] args){
final BankServiceWindows bankServiceWindows=new BankServiceWindows(2);
Thread tom=new Thread(){
public void run(){
bankServiceWindows.handle();
System.out.println("tom開始办理业务");
try {
this.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("tom结束办理业务");
bankServiceWindows.unhandle();
}
};
Thread jim=new Thread(){
public void run(){
bankServiceWindows.handle();
System.out.println("jim開始办理业务");
try {
this.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("jim结束办理业务");
bankServiceWindows.unhandle();
}
};
Thread jay=new Thread(){
public void run(){
bankServiceWindows.handle();
System.out.println("jay開始办理业务");
try {
this.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("jay结束办理业务");
bankServiceWindows.unhandle();
}
};
tom.start();
jim.start();
jay.start();
}
}
可能的输出结果为:
tom開始办理业务
jay開始办理业务
jay结束办理业务
tom结束办理业务
jim開始办理业务
jim结束办理业务
tom和jay差点儿同一时候開始办理业务,而jay结束后有空暇的服务窗体jim才过来。
这节主要讲的是怎样使用AQS构建自己的同步器。而且剖析了锁获取与释放的模板的逻辑,让你更好理解AQS的实现,最后分别给出了独占模式和共享模式的同步器实现的样例。相信你们搞清楚这两种方式的实现后。要构建更加复杂的同步器就知道力往哪里使了。

喜欢研究java的同学能够交个朋友。以下是本人的微信号:

Java并发框架——AQS之怎样使用AQS构建同步器相关推荐

  1. 深入理解Java并发框架AQS系列(四):共享锁(Shared Lock)

    深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 深入理解Java并发框架AQS系列(三):独占锁(Exclusive Lock) 深入 ...

  2. 死磕Java并发:J.U.C之AQS:CLH同步队列

    本文转载自公号:Java技术驿站 在上篇文章"死磕Java并发:J.U.C之AQS简介"中提到了AQS内部维护着一个FIFO队列,该队列就是CLH同步队列. CLH同步队列是一个F ...

  3. 【死磕Java并发】-----J.U.C之AQS:CLH同步队列

    原文出处:https://www.cmsblogs.com/category/1391296887813967872 『chenssy』 在上篇博客[死磕Java并发]-----J.U.C之AQS:A ...

  4. java并发框架支持锁包括,jdk1.8锁

    JDK1.8有什么锁?_李广进的博客-CSDN博客 2020年4月23日 18.排他锁(不包含),X锁,若事务T对数据对象A加上x锁,则只允许T读取和修改A,其他任何事务都不能再对A加任何类型的锁,直 ...

  5. java并发框架支持锁包括,tip/面试题_并发与多线程.md at master · 171437912/tip · GitHub...

    01. java用()机制实现了进程之间的同步执行 A. 监视器 B. 虚拟机 C. 多个CPU D. 异步调用 正解: A 解析: 监视器机制即锁机制 02. 线程安全的map在JDK 1.5及其更 ...

  6. 死磕Java并发:J.U.C之AQS简介

    本文转载自公众号: Java技术驿站 Java的内置锁一直都是备受争议的,在JDK 1.6之前,synchronized这个重量级锁其性能一直都是较为低下,虽然在1.6后,进行大量的锁优化策略(死磕J ...

  7. java 并发框架源码_某网Java并发编程高阶技术-高性能并发框架源码解析与实战(云盘下载)...

    第1章 课程介绍(Java并发编程进阶课程) 什么是Disruptor?它一个高性能的异步处理框架,号称"单线程每秒可处理600W个订单"的神器,本课程目标:彻底精通一个如此优秀的 ...

  8. java 并发框架源码_Java并发编程高阶技术-高性能并发框架源码解析与实战

    Java并发编程高阶技术-高性能并发框架源码解析与实战 1 _0 Z' @+ l: s3 f6 r% t|____资料3 Z9 P- I2 x8 T6 ^ |____coding-275-master ...

  9. java queues 性能_鸟瞰 Java 并发框架

    (给ImportNew加星标,提高Java技能) 来自:唐尤华 https://dzone.com/articles/a-birds-eye-view-on-java-concurrency-fram ...

  10. Java 并发框架全览,这个牛逼!

    来自:唐尤华 https://dzone.com/articles/a-birds-eye-view-on-java-concurrency-frameworks-1 1. 为什么要写这篇文章 几年前 ...

最新文章

  1. POJ2932Coneology(计算几何、平面扫描)
  2. nginx日志问题解决方法记录
  3. 【UAV】光流模块、测量速度、快速入门及安装使用
  4. Ubuntu_Win10双系统互换注意事项以及蓝屏解决方案
  5. 一个跨国银行的敏捷转型案例要点之Agile Center
  6. DOM和Diff算法你应该知道的那些事,快收藏!
  7. 前端Javascript与Nodejs的异同
  8. OCP DBA考证轻松过关详解(ZT)
  9. WebStrom 使用淘宝镜像
  10. MFC编程入门之十(对话框:设置对话框控件的Tab顺序)
  11. 成为弹唱高手的秘诀,看这一篇就足够
  12. 如何取消计算机中的0-9,告诉你如何关闭win10易升程序
  13. 十三、商城 - 商城架构-分布式Dubbo(1)
  14. 【转载】用Pwnage + Redsnow 制作完美越狱固件
  15. Linux时间同步(Fri Nov 16 12:12:13 Local time zone must be set--see zic manual page 2018)解决办法
  16. 从大数据+AI 谈谈概念与场景
  17. 彩色飘带字体怎么制作?AE教程教给你
  18. 关键链项目管理(一) - TOC, 约束理论
  19. Windows平台调试工具:DebugView
  20. Flash鼠绘入门第五课:绘制可口的樱桃-Flash鼠绘可口的樱桃(1)

热门文章

  1. DELPHI 禁止移动窗体
  2. 正确高效使用数据库不可不知的索引失效问题
  3. 程序员必备的代码审查(Code Review)清单
  4. Struts2的properties配置文件详解
  5. 可自设定长度,根据各种标点符号去分隔字符串
  6. hdu4971 流-最大权闭包
  7. 【开发环境】Windows 系统中使用 Makefile 构建脚本编译 C 程序 ( 下载并安装 TDM-GCC 编译器 | 配置环境变量 | 编译 Makefile 程序 )
  8. 【错误记录】Flutter 混合开发报错 ( Android 端与 Flutter 端 EventChannel 初始化顺序错误导致无法通信 | EventChannel 通信流程 )
  9. 【错误记录】国际化报错 ( “xxx“ is not translated in “zh“ (Chinese) )
  10. 【Android 安全】DEX 加密 ( Proguard 简介 | 默认 ProGuard 分析 )