抽象队列同步器AQS应用Lock

2024-01-03 00:48

本文主要是介绍抽象队列同步器AQS应用Lock,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  1. AQS特性

阻塞等待队列
共享/独占
公平/非公平
可重入
允许中断

  1. 锁的三大核心

自旋
lockSupport 来阻塞及唤醒
cas 算法 //比较与交换 unsafe 底层是依赖汇编指令 cmpxchg()
queue队列

AbstractQueuedSynchronizer
exclusiveOwnerThread 当前获取锁的线程是谁
aqs依赖一个整形变量state 为0 锁没被持有
队列是基于 内部类Node 双向链表 同步等待队列

可重入锁是state反复加1

  1. 多个线程竞争锁(公平锁)

获取当前线程
获取state 状态 ,如state为0 且 阻塞队列中没有其他线程则获取锁
exclusiveOwnerThread 指向当前线程
如state不为0,则判断当前持有锁的线程是不是自己,是自己则加1,如果不是自己持有的继续CAS。返回false,加锁失败。
加锁失败的线程直接加入队列

protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (!hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;
}
  1. tryAcquire(arg) 锁竞争逻辑

acquireQueued(addWaiter(Node.EXCLUSIVE), arg) 线程入队逻辑
队列中的Node 除了有共享,和独占之外的属性
waitState(整型) 标识当前节点的生命状态:信号量
sinnal =-1 可被唤醒
cancelled =1 出现异常 中断引起 需要被废弃
condition =-2 条件等待
propagate = -3 广播状态 传播
0 初始状态

public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();
}
  1. 入队操作

当线程入队时,位于head节点的线程会重新再抢一次锁
如果还没抢到锁,head节点才会把自己阻塞(此时第一轮循环把head节点置为sinnal=-1 代表可被唤醒。第二轮循环阻塞线程,并且判断线程是否有中断信号唤醒的),如果抢到锁则会直接出队列

注: head节点thread为null

final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)cancelAcquire(node);}
}

shouldParkAfterFailedAcquire(p, node)
waitState = 0 ->-1 在持有锁的线程T0在释放锁之后,要判断head节点的waitState 是否!=0 ,如果waitState!=0 成立会再次waitState = 0 ->-1 。要想唤醒排队的第一个线程T1,T1被唤醒准备继续走循环拿锁。在非公平的情况下可能还会再次失败,此时可能T3拿到了锁!而T1会被再次阻塞,head节点会再次经历两次循环 waitState = 0 ->-1

Park阻塞线程唤醒的两种方式
中断
release()

线程被中断唤醒:抛异常
cancelAcquire(node);//标记当前节点为canceld,信号量,我们要剔除这样的节点

  1. 阻塞队列 BlockingQueue

线程通信的一个工具,在任意时刻、不管并发有多高,在单jvm上,同一时间永远只有一个线程能对队列进行出队或者入队操作
线程安全的队列

以ArrayBlockingQueue 为例

public ArrayBlockingQueue(int capacity, boolean fair) {if (capacity <= 0)throw new IllegalArgumentException();this.items = new Object[capacity];lock = new ReentrantLock(fair); //创建锁notEmpty = lock.newCondition(); //条件对象notFull =  lock.newCondition(); //条件对象
}public void put(E e) throws InterruptedException {checkNotNull(e);final ReentrantLock lock = this.lock;lock.lockInterruptibly();     //生产者加锁try {while (count == items.length) //队列满了notFull.await();     enqueue(e);} finally {lock.unlock();}
}

//await可打开, 一进方法内,
1、先判断线程是否被中断,中断则抛出异常。
2、不被中断则会入Node队列(条件等待队列)。
3、通过锁状态释放锁。
4、通知CLH队列(竞争锁时线程的队列:同步队列)消费下一个节点。
注:线程获取的条件:只有在CLH队列里等待的node节点并且该节点的前一个结点是sinal,条件队列里的线程是不可以获取锁的。
注2:当有一个线程从queue队列中消费,留出一个空时。会发送一个sinal消息给条件队列这时候条件队列会转换成CLH队列

这篇关于抽象队列同步器AQS应用Lock的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/564118

相关文章

CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比

《CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比》CSS中的position属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布... css 中的 position 属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布局和层叠关

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

Java中常见队列举例详解(非线程安全)

《Java中常见队列举例详解(非线程安全)》队列用于模拟队列这种数据结构,队列通常是指先进先出的容器,:本文主要介绍Java中常见队列(非线程安全)的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一.队列定义 二.常见接口 三.常见实现类3.1 ArrayDeque3.1.1 实现原理3.1.2

Python使用Tkinter打造一个完整的桌面应用

《Python使用Tkinter打造一个完整的桌面应用》在Python生态中,Tkinter就像一把瑞士军刀,它没有花哨的特效,却能快速搭建出实用的图形界面,作为Python自带的标准库,无需安装即可... 目录一、界面搭建:像搭积木一样组合控件二、菜单系统:给应用装上“控制中枢”三、事件驱动:让界面“活”

如何确定哪些软件是Mac系统自带的? Mac系统内置应用查看技巧

《如何确定哪些软件是Mac系统自带的?Mac系统内置应用查看技巧》如何确定哪些软件是Mac系统自带的?mac系统中有很多自带的应用,想要看看哪些是系统自带,该怎么查看呢?下面我们就来看看Mac系统内... 在MAC电脑上,可以使用以下方法来确定哪些软件是系统自带的:1.应用程序文件夹打开应用程序文件夹

解决mysql插入数据锁等待超时报错:Lock wait timeout exceeded;try restarting transaction

《解决mysql插入数据锁等待超时报错:Lockwaittimeoutexceeded;tryrestartingtransaction》:本文主要介绍解决mysql插入数据锁等待超时报... 目录报错信息解决办法1、数据库中执行如下sql2、再到 INNODB_TRX 事务表中查看总结报错信息Lock

C++ RabbitMq消息队列组件详解

《C++RabbitMq消息队列组件详解》:本文主要介绍C++RabbitMq消息队列组件的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. RabbitMq介绍2. 安装RabbitMQ3. 安装 RabbitMQ 的 C++客户端库4. A

Python Flask 库及应用场景

《PythonFlask库及应用场景》Flask是Python生态中​轻量级且高度灵活的Web开发框架,基于WerkzeugWSGI工具库和Jinja2模板引擎构建,下面给大家介绍PythonFl... 目录一、Flask 库简介二、核心组件与架构三、常用函数与核心操作 ​1. 基础应用搭建​2. 路由与参

Spring Boot中的YML配置列表及应用小结

《SpringBoot中的YML配置列表及应用小结》在SpringBoot中使用YAML进行列表的配置不仅简洁明了,还能提高代码的可读性和可维护性,:本文主要介绍SpringBoot中的YML配... 目录YAML列表的基础语法在Spring Boot中的应用从YAML读取列表列表中的复杂对象其他注意事项总

golang实现延迟队列(delay queue)的两种实现

《golang实现延迟队列(delayqueue)的两种实现》本文主要介绍了golang实现延迟队列(delayqueue)的两种实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录1 延迟队列:邮件提醒、订单自动取消2 实现2.1 simplChina编程e简单版:go自带的time