Aqs独占/共享模式

独占锁和共享锁的概念

独占锁也叫排他锁,是指该锁一次只能被一个线程所持有。如果线程T对数据A加上排他锁后,则其他线程不能再对A加任何类型的锁。获得排它锁的线程即能读数据又能修改数据。

共享锁是指该锁可被多个线程所持有。如果线程T对数据A加上共享锁后,则其他线程只能对A再加共享锁,不能加排它锁。获得共享锁的线程只能读数据,不能修改数据。

之前的分析了ReentrantLock,Semaphore, CountDownLatch这三个典型的aqs实现。其中ReentrantLock使用了独占模式,Semaphore和CountDownLatch是共享模式

Aqs独占锁

如下图所示:
在这里插入图片描述

只能有一个线程获取到锁,其它线程则每次加入到CLH尾部阻塞等待。

测试代码

 static ReentrantLock reentrantLock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {Runnable runnable = () -> {try {reentrantLock.lock();// 业务处理TimeUnit.SECONDS.sleep(2);System.out.println(Thread.currentThread().getName() + ":" + " finished");} catch (Exception e) {e.printStackTrace();} finally {reentrantLock.unlock();}};List<Thread> threads = new ArrayList<>(4);for(int i= 0;i<6;i++) {Thread thread = new Thread(runnable, String.valueOf((char)('A' + i)));threads.add(thread);}for(Thread thread: threads){thread.start();}}

先理解一下aqs的Node状态

static final class Node {/** Marker to indicate a node is waiting in shared mode */static final Node SHARED = new Node();/** Marker to indicate a node is waiting in exclusive mode */static final Node EXCLUSIVE = null;/** waitStatus value to indicate thread has cancelled. */static final int CANCELLED =  1;/** waitStatus value to indicate successor's thread needs unparking. */static final int SIGNAL    = -1;/** waitStatus value to indicate thread is waiting on condition. */static final int CONDITION = -2;/*** waitStatus value to indicate the next acquireShared should* unconditionally propagate.*/static final int PROPAGATE = -3;

CANCELLED(1):表示当前结点已取消调度。当timeout或被中断(响应中断的情况下),会触发变更为此状态,进入该状态后的结点将不会再变化。
SIGNAL(-1):表示后继结点在等待当前结点唤醒。后继结点入队时,会将前继结点的状态更新为SIGNAL。
CONDITION(-2):表示结点等待在Condition上,当其他线程调用了Condition的signal()方法后,CONDITION状态的结点将从等待队列转移到同步队列中,等待获取同步锁。
PROPAGATE(-3):共享模式下,前继结点不仅会唤醒其后继结点,同时也可能会唤醒后继的后继结点。
0:新结点入队时的默认状态。

可以看到负值表示结点处于有效等待状态,而正值表示结点已被取消。

java.util.concurrent.locks.AbstractQueuedSynchronizer#acquire

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

如果tryAcquire返回false, 则进行acquireQueued(addWaiter(Node.EXCLUSIVE), arg)操作

addWaiter(Node.EXCLUSIVE) 即addWaiter(null)
在这里插入图片描述

再来看释放锁的唤醒逻辑

当独占线程执行结束释放锁的成功过后,执行如下
在这里插入图片描述
显然当执行tryRelease成功后head不是null且其等待状态是唤醒状态-1; 所以能执行唤醒下一个节点的操作,即unparkSuccessor方法

aqs unparkSuccessor(Node node)方法

 private void unparkSuccessor(Node node) {/** If status is negative (i.e., possibly needing signal) try* to clear in anticipation of signalling.  It is OK if this* fails or if status is changed by waiting thread.*/int ws = node.waitStatus;if (ws < 0)node.compareAndSetWaitStatus(ws, 0);/** Thread to unpark is held in successor, which is normally* just the next node.  But if cancelled or apparently null,* traverse backwards from tail to find the actual* non-cancelled successor.*/Node s = node.next;if (s == null || s.waitStatus > 0) {s = null;for (Node p = tail; p != node && p != null; p = p.prev)if (p.waitStatus <= 0)s = p;}if (s != null)LockSupport.unpark(s.thread);}

首先设置了当前node等待状态为初始化值,然后判断下一节点是否是有效等待状态(>0的判断); 接着

从等待队列的尾部开始往前依次判断每个节点是否是有效等待状态,最后找到的节点即时要进行唤醒的(执行 LockSupport.unpark(s.thread);)操作

s = null;
for (Node p = tail; p != node && p != null; p = p.prev)if (p.waitStatus <= 0)s = p;
为什么从尾到头的判断?

因为如队列是从尾部直接加入的,可能还没有设置上一节点的next操作, 有并发问题。可能是刚加入的新等待节点,这样从尾部判断就不会漏掉了

private Node enq(final Node node) {for (;;) {Node t = tail;if (t == null) { // Must initialize//队列为空需要初始化,创建空的头节点if (compareAndSetHead(new Node()))tail = head;} else {node.prev = t;//set尾部节点if (compareAndSetTail(t, node)) {//当前节点置为尾部t.next = node; //前驱节点的next指针指向当前节点return t;}}}
}

Aqs共享锁

共享模式一般是有个资源初始值,然后多个线程共享使用
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/140268.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

应用程序转换工具Unite mac中文版软件特点

Unite mac是一款Mac平台上的应用程序转换工具&#xff0c;它可以将任何网站或Web应用程序转换成本地应用程序&#xff0c;以便更方便地访问和使用。 Unite mac软件特点 网站转应用程序&#xff1a;该软件可以将任何网站或Web应用程序转换成本地应用程序&#xff0c;方便用户更…

技术贴 | 深度解析 PostgreSQL Protocol v3.0(二)— 扩展查询

引言 PostgreSQL 使用基于消息的协议在前端&#xff08;客户端&#xff09;和后端&#xff08;服务器&#xff09;之间进行通信。该协议通过 TCP/IP 和 Unix 域套接字支持。 《深度解析 PostgreSQL Protocol v3.0》系列技术贴&#xff0c;将带大家深度了解 PostgreSQL Protoc…

栈和队列-Java

目录 一、栈 1.1 概念 1.2 栈的使用 1.3 栈的模拟实现 1.4 栈的应用场景 1.5 概念区分 二、队列 2.1 概念 2.2 队列的使用 2.3 队列的模拟实现 2.4 循环队列 三、双端队列 四、面试题 一、栈 1.1 概念 栈&#xff1a;一种特殊的线性表&#xff0c;只允许在固定的一端进行插…

69、Spring Data JPA 的 @Query查询 和 命名查询(半自动:提供 SQL 或 JPQL 查询)

1、方法名关键字查询&#xff08;全自动&#xff0c;既不需要提供sql语句&#xff0c;也不需要提供方法体&#xff09; 2、Query查询&#xff08;半自动&#xff1a;提供 SQL 或 JPQL 查询&#xff09; 3、自定义查询&#xff08;全手动&#xff09; Query查询 和 命名查询的区…

Hive 的函数介绍

目录 ​编辑 一、内置运算符 1.1 关系运算符 1.2算术运算符 1.3逻辑运算符 1.4复杂类型函数 1.5对复杂类型函数操作 二、内置函数 2.1数学函数 2.2收集函数 2.3类型转换函数 2.4日期函数 2.5条件函数 2.6字符函数 三、内置的聚合函数 四、内置表生成函数 五、…

nginx知识点详解:反向代理+负载均衡+动静分离+高可用集群

一、nginx基本概念 1. nginx是什么&#xff0c;做什么事情&#xff1f; Nginx是一个高性能的HTTP和反向代理服务器&#xff0c;特点是占有内存少&#xff0c;并发能力强。Nginx转为性能优化而开发&#xff0c;能经受高负载考验。支持热部署&#xff0c;启动容易&#xff0c;运…

三叠云电梯维保系统,全面提升电梯维保管理效率与质量

随着城市化进程的不断加速&#xff0c;电梯已成为现代建筑中不可或缺的交通工具。然而&#xff0c;电梯的安全和正常运行对于居民和物业公司来说至关重要&#xff0c;同时电梯维保一直是一个困扰物业管理公司和维保企业的难题。传统的维保方式因纸质记录的繁琐和错误频发&#…

整合车辆出险报告Api接口,轻松管理车险理赔!

随着车辆保有量的不断增加&#xff0c;车辆出险的情况也越来越普遍。对于车主来说&#xff0c;如何高效地管理车险理赔&#xff0c;处理保险事故是非常重要的。这时候我们就可以借助整合车辆出险报告API接口&#xff0c;实现快速定位理赔信息&#xff0c;轻松管理车险理赔。 一…

k8s 集群 -4 pod生命周期

首先 容器环境初始化,pod 由pod 镜像来提供 在pod 生命周期里 容器主要 分文两种&#xff1a;初始化容器和主容器 初始化 容器一定要成功运行并退出&#xff0c;当初始化容器运行退出完了之后 主容器开始和运行 主容器开始运行的时候 有两个探针 存活探针和就绪探针 Pod 可…

git reset origin --hard解决‘Your branch is ahead of ‘origin/xxxx‘ by xx commit.’

git reset origin --hard解决‘Your branch is ahead of origin/xxxx by xx commit.’ 如图&#xff1a; 之前是这么解决的解决git&#xff1a;Your branch is ahead of ‘XXX‘ by X commits-CSDN博客git删除/撤销远已经push到程服务器上某次代码提交场景&#xff1a;不小心把…

3D成像技术概述

工业4.0时代,三维机器视觉备受关注,目前,三维机器视觉成像方法主要分为光学成像法和非光学成像法,这之中,光学成像法是市场主流。 飞行时间3D成像 飞行时间成像(Time of Flight),简称TOF,是通过给目标连续发送光脉冲,然后用传感器接收从物体返回的光,通过探测光脉…

自动化测试框架Playwright安装以及使用

最近&#xff0c;微软开源了一个非常强大的自动化项目叫 playwright-python 它支持主流的浏览器&#xff0c;包含&#xff1a;Chrome、Firefox、Safari、Microsoft Edge 等&#xff0c;同时支持以无头模式、有头模式运行&#xff0c;并提供了同步、异步的 API&#xff0c;可以…

基于微服务的第二课堂管理系统(素质拓展学分管理平台)SpringCloud、SpringBoot 分布式,微服务

基于微服务的第二课堂管理系统 一款真正的企业级开发项目&#xff0c;采用标准的企业规范开发&#xff0c;有项目介绍视频和源码&#xff0c;需要学习的同学可以拿去学习&#xff0c;这是一款真正可以写在简历上的校招项目&#xff0c;能够真正学到东西的一个项目&#xff0c;话…

OpenGL之坐标系统

将坐标变换为标准化设备坐标&#xff0c;接着再转化为屏幕坐标的过程通常是分步进行的&#xff0c;也就是类似于流水线那样子。在流水线中&#xff0c;物体的顶点在最终转化为屏幕坐标之前还会被变换到多个坐标系统(Coordinate System)。将物体的坐标变换到几个过渡坐标系(Inte…

【1993. 树上的操作】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你一棵 n 个节点的树&#xff0c;编号从 0 到 n - 1 &#xff0c;以父节点数组 parent 的形式给出&#xff0c;其中 parent[i] 是第 i 个节点的父节点。树的根节点为 0 号节点&#xff0c;所以 par…

Word中对象方法(Methods)的理解及示例(下)

【分享成果&#xff0c;随喜正能量】当你的见识多了&#xff0c;眼界宽了&#xff0c;格局大了&#xff0c;所有的磨难都将不再是磨难&#xff0c;而是助你成长的阶梯。 。 《VBA之Word应用》&#xff08;10178982&#xff09;&#xff0c;是我推出第八套教程&#xff0c;教程…

机械寿命预测(基于NASA C-MAPSS数据的剩余使用寿命RUL预测,Python代码,CNN_LSTM模型,有详细中文注释)

1.效果视频&#xff1a;机械寿命预测&#xff08;NASA涡轮风扇发动机剩余使用寿命RUL预测&#xff0c;Python代码&#xff0c;CNN_LSTM模型&#xff0c;有详细中文注释&#xff09;_哔哩哔哩_bilibili 环境库版本&#xff1a; 2.数据来源&#xff1a;https://www.nasa.gov/int…

Linux0.11——第二回 从0x7c00到0x90000

上一讲&#xff0c;讲了CPU执行操作系统的最开始的两行代码&#xff1a; mov ax, 0x07c0 mov ds, ax这两行代码将数据段寄存器 ds 的值变成了 0x07c0&#xff0c;方便之后访问内存时&#xff0c;利用这个段基址进行寻址。 接下来的代码&#xff1a; mov ax,0x9000 mov es,ax…

解决方案:TSINGSEE青犀+智能分析网关助力智慧仓储智能化监管

为全面保障物流仓储的安全性与完整性&#xff0c;解决仓库管理难题&#xff0c;优化物流仓储方式&#xff0c;提升仓储效率&#xff0c;降低人工成本&#xff0c;旭帆科技推出智慧仓储AI视频智能分析方案&#xff0c;利用物联网、大数据、云计算等技术&#xff0c;对仓储管理进…

【C刷题】day3

一、选择题 1、已知函数的原型是&#xff1a; int fun(char b[10], int *a); &#xff0c;设定义&#xff1a; char c[10];int d; &#xff0c;正确的调用语句是&#xff08; &#xff09; A: fun(c,&d); B: fun(c,d); C: fun(&c,&d); D: fun(&c,d); 【答案…