AQS

什么是AQS?

是阻塞式锁和相关同步器工具的框架,如ReentrantLock内部就持有这个同步器,具体实现都是调用同步器的API实现加锁解锁

==========================ReentrantLock中的Sync================================private final ReentrantLock.Sync sync;public ReentrantLock() {//默认非公平this.sync = new ReentrantLock.NonfairSync();}
==========================Sync继承自AQS========================================abstract static class Sync extends AbstractQueuedSynchronizer

AQS特点


AQS采用模板模式:tryXXX方法是需要子类需要实现的,而Acquire是AQS提供的,调用的是tryXXX

//获取锁
public final void acquire(int arg) {if (!this.tryAcquire(arg) && this.acquireQueued(this.addWaiter(AbstractQueuedSynchronizer.Node.EXCLUSIVE), arg)) {selfInterrupt();}}//AQS只抛出异常
protected boolean tryAcquire(int arg) {throw new UnsupportedOperationException();}

AQS中的组件

主要有三个组件:State,ConditionObject,CHL队列

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements Serializable {//CHL队列private transient volatile AbstractQueuedSynchronizer.Node head;private transient volatile AbstractQueuedSynchronizer.Node tail;//资源状态位private volatile int state;static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;//条件变量public class ConditionObject implements Condition, Serializable {private static final long serialVersionUID = 1173984872572414699L;private transient AbstractQueuedSynchronizer.Node firstWaiter;private transient AbstractQueuedSynchronizer.Node lastWaiter;private static final int REINTERRUPT = 1;private static final int THROW_IE = -1;}
//............
}

state:共享资源状态
ConditionObject:条件变量,把对资源争用的线程划分为不同种类,可根据条件对特定一组线程唤醒,条件变量上的等待队列是单链表

public static void main(String[] args) throws InterruptedException {ReentrantLock reentrantLock = new ReentrantLock();Condition condition1 = reentrantLock.newCondition();Condition condition2 = reentrantLock.newCondition();condition1.await();condition2.await();}

CHL队列:CHL队列是双向链表,在AQS中直接等待的队列,AQS中用head,tail指向头尾。

public static void main(String[] args) throws InterruptedException {ReentrantLock reentrantLock = new ReentrantLock();reentrantLock.wait();}

Node

上面说的等待队列中的节点是把线程做了一层封装,先看一下Node中重要的成员变量

static final class Node {static final AbstractQueuedSynchronizer.Node SHARED = new AbstractQueuedSynchronizer.Node();static final AbstractQueuedSynchronizer.Node EXCLUSIVE = null;//waitStatus描述,暂时不讨论其含义static final int CANCELLED = 1;static final int SIGNAL = -1;static final int CONDITION = -2;static final int PROPAGATE = -3;volatile int waitStatus;//前驱与后继节点volatile AbstractQueuedSynchronizer.Node prev;volatile AbstractQueuedSynchronizer.Node next;//节点中包含的线程volatile Thread thread;//下一个等待的节点AbstractQueuedSynchronizer.Node nextWaiter;//...........
}

知道了上面的基础知识就可以手动实现一个不可重入锁了

自定义锁

class myLock implements Lock {//独占锁,同步器内部类class MySync extends AbstractQueuedSynchronizer {@Override//加锁protected boolean tryAcquire(int arg) {//state变量加了volatileif (compareAndSetState(0,1)){//设置当前线程setExclusiveOwnerThread(Thread.currentThread());}return true;}@Override//解锁protected boolean tryRelease(int arg) {setExclusiveOwnerThread(null);//由于是独占锁,setState无需同步处理。但是必须在上一行之后,//因为volatile保证前面的操作能被其他线程读取,所以先把持有锁的线程设置为nullsetState(0);return true;}@Override//是否持有独占锁protected boolean isHeldExclusively() {return getState() == 1;}public Condition newCondition(){return new ConditionObject();}}MySync sync = new MySync();@Override//加锁public void lock() {sync.acquire(1);}@Override//加锁,可打断public void lockInterruptibly() throws InterruptedException {sync.acquireInterruptibly(1);}@Override//尝试加锁(一次)public boolean tryLock() {return sync.tryAcquire(1);}@Override//超时加锁public boolean tryLock(long l, TimeUnit timeUnit) throws InterruptedException {return sync.tryAcquireNanos(1,timeUnit.toNanos(l));}@Override//解锁public void unlock() {sync.release(1);}@Override//创建条件变量public Condition newCondition() {return sync.newCondition();}
}

发现没有,实现一个简易的自制锁是如此简单,因为AQS底层已经封装好了必要的方法,后面说的ReentrantLock也是在此模板上进行扩展

ReentrantLock

特点


不可打断模式:在未获得锁的时候被打断仅会加上打断标记,在未获得锁的过程中对打断置之不理,继续驻留在队列。获得锁后会继续运行,只是打断标记变为true

可打断模式:尝试获得锁的过程中被打断就不会进入获取资源的for循环,会终止获得锁的行为,直接抛出异常

try {//如果获取失败进入阻塞队列,这时可以被其他线程interrupt打断reentrantLock.lockInterruptibly();
} catch (InterruptedException e) {//打断后操作e.printStackTrace();
}

非公平锁:不检查AQS队列,直接加锁。默认不公平,公平锁会降低并发度,非必要不使用

公平锁:先检查AQS队列,如果队列中没有第二或者第二节点不是当前线程则不会去竞争锁

ReentrantLock获取锁后执行的代码在try块中执行, Lock比Synchronize更广泛,且需要手动加锁解锁。发生异常时要在finally中释放锁,否则会造成死锁。

特定唤醒

为了便于理解ReentrantLock相对于Synchronize的特性,我们来实现一个特定唤醒的例子
通过标志位flag和condition来做到指定唤醒某个线程

class Share{private Lock lock = new ReentrantLock();private Condition c1 = lock.newCondition();private Condition c2 = lock.newCondition();private int flag = 1;public void a1() throws InterruptedException {lock.lock();try {while (flag != 1){c1.await();}System.out.println("do a1........");flag = 2;//c1执行完唤醒c2里的线程c2.signal();}finally {lock.unlock();}}public void a2() throws InterruptedException {lock.lock();try {while (flag != 2){c2.await();}System.out.println("do a2........");flag = 1;//c2执行完唤醒c1里的线程c1.signal();}finally {lock.unlock();}}
}

本篇总结

此篇文章初步了解了AQS和ReentrantLock的概念及特性,下一篇我们会深入了解它们之间底层的实现

从ReentrantLock出发看AQS(一)相关推荐

  1. 从ReentrantLock角度解析AQS

    一.概述 闲来不卷,随便聊一点. 一般情况下,大家系统中至少也是JDK8了,那想必对于JDK5加入的一系列功能并不陌生吧.那时候重点加入了java.util.concurrent并发包,我们简称为JU ...

  2. synchronized锁的级别和ReentrantLock锁(AQS)

    目录 synchronized synchronized锁的特点 synchronized锁级别 无锁 偏向锁 轻量级锁 重量级锁 自旋锁 锁消除 ReentrantLock 公平锁和非公平锁 AQS ...

  3. 从ReentrantLock的实现看AQS的原理及应用

    来自:美团技术团队 AQS作为JUC中构建锁或者其他同步组件的基础框架,应用范围十分广泛,这篇文章会带着大家从可重入锁一点点揭开AQS的神秘面纱. 前言 Java中的大部分同步类(Lock.Semap ...

  4. Java多线程——带你看AQS框架源码

    AQS,全称AbstractQueuedSynchronizer,是Concurrent包锁的核心,没有AQS就没有Java的Concurrent包.它到底是个什么,我们来看看源码的第一段注解是怎么说 ...

  5. c语言mn间有多少素数,素数表达式p=2a+1 (a ≠ 2mn+m+n)由此出发看哥猜、挛猜比较清晰...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 zzzvipsinacom的贴子:偶数2N+4至少可以表示为N/(2Sqr(2N+1))个素数对之和,其贡献在于:将模糊的哥猜.挛猜等问题,推演.变换成为 ...

  6. 《大数据+AI在大健康领域中最佳实践前瞻》---- 以元数据管理角度出发看人工智能医疗器械标准数据集的构建

    文章大纲 元数据治理 构建思路 我国数据集构建的规则 外国数据集构建思路参考 构建过程中需要注意的问题 数据收集SOP(Standard Operating Procedure) 元数据收集 数据收集 ...

  7. 沉淀再出发:关于java中的AQS理解

    沉淀再出发:关于java中的AQS理解 一.前言 在java中有很多锁结构都继承自AQS(AbstractQueuedSynchronizer)这个抽象类如果我们仔细了解可以发现AQS的作用是非常大的 ...

  8. 深入剖析AQS和CAS,看了都说好

    AQS简介 AQS(AbstractQueuedSynchronizer)为「抽象队列同步器」,简单的说「AQS就是一个抽象类」,抽象类就是AbstractQueuedSynchronizer,没有实 ...

  9. 这篇 ReentrantLock 看不懂,加我我给你发红包

    来自:Java建设者 回答一个问题 在开始本篇文章的内容讲述前,先来回答我一个问题,为什么 JDK 提供一个 synchronized 关键字之后还要提供一个 Lock 锁,这不是多此一举吗?难道 J ...

最新文章

  1. linux 常用命令:
  2. springboot多模块打包指定子模块环境配置文件
  3. 006-筛选分类排序搜索查找Filter-Classificatio-Sort-Search-Find-Seek-Locate
  4. 文件过滤_jmeter(七)-BeanShell对数据过滤保存文件
  5. python3 readexcel pandas问题,使用python中的pandas中的read_excel函数将日期保留为字符串...
  6. HTML和css学术报告,清华大学 张超 副教授访问我院并做学术报告
  7. pandas读写csv
  8. Thinkphp开发时关闭缓存的方法
  9. Perl的Net::SSH::Perl模块实现远程登陆ssh
  10. Pravega Flink connector 的过去、现在和未来
  11. 51nod1183编辑距离----DP--字符串最小变化
  12. bootstrape常用标签_bootstrap 常用data
  13. rainmeter使用教程_如何使用Rainmeter在桌面上显示报价
  14. pktgen-dpdk 进行rfc2544测试
  15. 免费开放的电子图书馆
  16. 工商管理企业经营战略知识归纳
  17. Unity Gyro之使用陀螺仪实现简单VR全景环视效果
  18. 使用Audacity分析浊音、清音和爆破音的时域以及频域特征
  19. tongweb7启动参数配置配置个人理解
  20. uni.showToast() 提示

热门文章

  1. 汽车媒体行业急速飞奔,汽车之家、易车网、杉车网新模式加持助力
  2. 毕业设计-深度学习在自动驾驶领域应用
  3. 抗干扰矩阵键盘按键消抖
  4. 人工智能芯片能为Mate 10拍照带来什么?华为工程师这么解答
  5. bzoj2300【HAOI2011】防线修建
  6. 洛谷 P1966 火柴排队【树状数组】
  7. HTML语言基本语法规范
  8. Unity --- 动画分层
  9. 建筑绿色化进展神速 新建建筑绿色化已超90%
  10. 解决json解析报错:Expecting value: line 1 column 1 (char 0)