AQS 概述

AQS(队列同步器,AbstractQueuedSynchronizer),是用来构建锁或其他同步组件的核心基础框架(比如 ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch)

AQS的底层结构是:一个整型变量state表示同步状态,一个内置的FIFO队列(同步队列)来实现资源获取线程的同步等待排队,若干个FIFO队列(条件等待队列)来完成持有资源线程的条件等待排队。同步队列如下:

AQS的使用方式

同步器的设计是基于模板方法模式的,其使用方式是继承,子类通过继承同步器并重写指定的模板方法,模板方法分为3类:独占式获取与释放同步状态、共享式获取与释放同步状态、查询队列中的等待线程。在重写过程中可以使用同步器提供的3个方法来管理同步状态state:getState()、setState()和compareAndSetState(),因为它们能够保证state的改变是并发安全的。

当实现一个自定义同步组件时,推荐在内部聚合/组合一个同步器的实现类,该自定义同步组件将通过调用同步器提供的模板方法来实现自己的同步语义。为什么不直接使用同步器呢?因为同步器自身没有实现任何同步接口,它仅仅是定义了若干管理同步状态的方法,这样有利于实现各种类型的同步组件

同步器与锁的关系

同步器是实现锁的关键,在锁的实现中聚合/组合了一个同步器,利用该同步器实现了锁的语义。

可以这样理解二者之间的关系:锁是面向使用者的,它定义了使用者与锁的交互接口,隐藏了实现细节;而同步器面向的是锁的实现者,它简化了锁的实现方式,包括屏蔽同步状态管理、线程的排队、等待与唤醒等底层操作。锁和同步器很好地隔离了使用者和实现者所需关注的领域。

AQS:获取与释放同步状态

1.独占式获取同步状态

查看源码 AbstractQueuedSynchronizer.acquire(..)

public final void acquire(int arg) {
//tryAcquire(..) 尝试获取同步状态,由子类重写,最经典的实现是互斥锁:state=0(锁自由),state>0(锁被占用)
//acquireQueued(..) 进入同步队列,阻塞等待获取锁
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}

由于acquire(..)方法不响应中断,因此AQS也提供了响应中断、超时等待的方法:acquireInterruptibly(..)、tryAcquireNanos(..)

2.独占式释放同步状态

查看源码 AbstractQueuedSynchronizer.release(..)

public final boolean release(int arg) {
//tryAcquire(..) 尝试释放同步状态,由子类重写
if (tryRelease(arg)) {
Node h = head;
//unparkSuccessor(..) 唤醒被挂起的Node(线程)
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}

3.共享式获取同步状态

查看源码 AbstractQueuedSynchronizer.acquireShared(..)

public final void acquireShared(int arg) {
//tryAcquireShared(..) 尝试获取同步状态,由子类重写,最经典的实现是信号量:state>0(锁很多),state<0(锁不足)
//doAcquireShared(..) 进入同步队列,阻塞等待获取锁
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}

由于acquireShared(..)方法不响应中断,因此AQS也提供了响应中断、超时等待的方法:acquireSharedInterruptibly(..)、tryAcquireSharedNanos(..)

4.共享式释放同步状态

查看源码 AbstractQueuedSynchronizer.

public final boolean releaseShared(int arg) {
//tryReleaseShared(..) 尝试释放同步状态,由子类重写
if (tryReleaseShared(arg)) {
//doReleaseShared(..) 唤醒被挂起的Node(线程)
doReleaseShared();
return true;
}
return false;
}

参考文章:

Java AQS 概述的更多相关文章

  1. Java AQS学习

    参考原文: Java并发之AQS详解 <Java并发编程的艺术> AQS 概述 AQS简介 AQS(AbstractQueuedSynchronizer)就是一个抽象的队列同步器,它是用来 ...

  2. Java Annotation概述

    @(Java)[Annotation|Java] Java Annotation概述 用途 编译器的相关信息,如用于检测错误和一些警告 编译时和部署时的处理,如一些软件用于自动生成代码之类的 运行时处 ...

  3. 《java集合概述》

    JAVA集合概述: Collection: |---List有序的:通过索引就可以精确的操作集合中的元素.元素是可以重复的. List提供了增删改查的动作. 增加add(element) add(in ...

  4. Java的概述以及语法

    Java的语法分为标示符和数据类型 Java的概述: 一些手打的: long l = 12345; //隐式转换 int a = (int)121234567L; //强制转换 float f =12 ...

  5. Java集合概述、Set集合(HashSet类、LinkedHashSet类、TreeSet类、EnumSet类)

    Java集合概述.Set集合(HashSet类.LinkedHashSet类.TreeSet类.EnumSet类) 1.Java集合概述1)数组可以保存多个对象,但数组长度不可变,一旦在初始化数组时指 ...

  6. Java笔记:Java集合概述和Set集合

    本文主要是Java集合的概述和Set集合 1.Java集合概述 1)数组可以保存多个对象,但数组长度不可变,一旦在初始化数组时指定了数组长度,这个数组长度就是不可变的,如果需要保存数量变化的数据,数组 ...

  7. Java NIO学习笔记一 Java NIO概述

    Java NIO概述 Java NIO(新的IO)是Java的替代IO API(来自Java 1.4),这意味着替代标准的 java IO和java Networking API.Java NIO提供 ...

  8. java基础---java语言概述

    一.计算机编程的两种范型 1.面向过程的模型---具有线性执行特点,认为是代码作用于数据. 2.面向对象的模型---围绕它的数据(即对象)和为这个数据定义的接口来组织程序:实际上是用数据控制代码的访问 ...

  9. Java核心技术(Java白皮书)卷Ⅰ 第一章 Java程序设计概述

    第1章 Java程序设计概述1.1 Java程序设计平台 具有令人赏心悦目的语法和易于理解的语言,与其他许多优秀语言一样,Java满足这些要求. 可移植性 垃圾收集 提供大型的库  如果想要有奇特的绘 ...

随机推荐

  1. Oracle 函数 Function

    定义 函数用于计算和返回一个结果值,把经常需要进行的计算写成函数,函数的调用是表达式的一部分.     函数与过程在创建的形式上有些相似,也是编译后放在内存中供用户使用.     函数必须有一个返回值 ...

  2. 解决用友U8删除用户时提示“用户已启用”不能删除的问题

    USE UFSystem go DECLARE @cUser_Id NVARCHAR(20) SET @cUser_Id='用户的登录名' DELETE l FROM dbo.UA_TaskLog l ...

  3. web项目 easyui-datagrid开发实践

    一,引言 工作的需要,做了3年的wpf(mvvm)……,又因为项目的需求,回归到web的开发. ■  3 years ago,vue是我三年前没用过的玩意儿. ■  3 years ago,boots ...

  4. ReactNative问题随记1 Exception in thread "main" java.lang.RuntimeException: gradle-2.14.1-all.zip

    ReactNative问题随记 想运行在真机上,在运行命令react-native run-android遇到错误如下: Scanning 559 folders for symlinks in D: ...

  5. 位运算-出现k次与出现一次

    题目:数组中arr只有一个数出现了1次,其他的数都出现了k次,请输出这个只出现了一次的数. 思路:这道题目要求使用位运算实现,如果采用数据结构Map就会简单很多.解此题前先了解不进位加法的思想,比如两 ...

  6. SUSE12Sp3安装配置.net core 生产环境(1)-IP,DNS,网关,SSH,GIT

    1.新增用户 sudo useradd 用户名 sudo passwd 用户名 这个时候会提示你输入密码,输入两次密码即可 2.静态 IP 设置 1.设置 IP 地址 sudo vi /etc/sys ...

  7. websocket+rabbitmq实战

    1. websocket+rabbitmq实战 1.1. 前言   接到的需求是后台定向给指定web登录用户推送消息,且可能同一账号会登录多个客户端都要接收到消息 1.2. 遇坑 基于springbo ...

  8. Java面试题中的Redis大合集,所有你想找的都在这里!

    概述 Redis 是一个开源的,基于内存的结构化数据存储媒介,可以作为数据库.缓存服务或消息服务使用.``` Redis 支持多种数据结构,包括字符串.哈希表.链表.集合.有序集合.位图.Hyperl ...

  9. java线程阻塞唤醒的四种方式

    java在多线程情况下,经常会使用到线程的阻塞与唤醒,这里就为大家简单介绍一下以下几种阻塞/唤醒方式与区别,不做详细的介绍与代码分析 suspend与resume Java废弃 suspend() 去 ...

  10. python传入不确定个数参数

    Python3自带的一个函数为 zip ,使用方式如下: In: print zip([1, 2],[3, 4]) Out: [(1, 3), (2, 4)] In: print zip([1, 2] ...