javalock(四)AQS派生类之Semphore逐行注释
简单概括:
Semphore是一把共享锁(即读锁),即实现了AQS的tryAcquireShared&&tryReleaseShared函数
Semphore的逻辑是这样:
创建semphore的时候会初始化一个锁容量即permits,即最多同时允许permits个线程获取读锁资源。AQS的state在semphore中表示锁资源的剩余容量。Semphore.tryAcquireShared就是如果锁资源剩余容量大于0则表示可以成功获取锁,然后锁资源容量减一,Semphore的tryReleaseShared就是锁资源容量+1。
笔记:
semphore没有锁所有者的概念,只有资源剩余量的概念,也就是说不管你是谁,只要资源还有剩余,那么就允许访问,也就是说一个线程可以获取多次资源
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;public class Semaphore implements java.io.Serializable {private static final long serialVersionUID = -3222578661600680210L;private final Sync sync;abstract static class Sync extends AbstractQueuedSynchronizer {private static final long serialVersionUID = 1192457210091910933L;Sync(int permits) {//state就是表示锁资源剩余量setState(permits);}final int getPermits() {return getState();}//尝试获取共享锁资源。while cas方式扣减,准确说是:do{}while(!CAS)//获取锁资源的逻辑就是:如果锁资源剩余容量大于0就允许立即获得锁而无需入aqs队列排队//反之则获取失败,返回false//semphore没有锁所有者的概念,只有资源剩余量的概念//也就是说不管你是谁,只要资源还有剩余,那么就允许访问//也就是说一个线程可以获取多次资源final int nonfairTryAcquireShared(int acquires) {for (;;) {//笔记:getState是非并发安全的,但是没关系,//因为getState的返回值只是用来快速判断是否有资源剩余//真正决定能否成功获得锁的还是cas(available,remainging)这个操作//也就是说这里是一个乐观的做法:先扣减,再写回,如果冲突了就重试//通过getState获取资源剩余量int available = getState();//先计算要扣减的资源量int remaining = available - acquires;//如果remaining小于0表示资源剩余量小于0则,此时无法成功获取锁,所以返回负数//如果compareAndSetState(available, remaining)成功则表明资源剩余量大于0//并且资源扣减成功,此时remaing大于等于0,表示获取锁成功,所以返回非负数if (remaining < 0 ||compareAndSetState(available, remaining))return remaining;//走到这里则进入下一轮循环重试}}//尝试释放锁资源,也是do{}while(!cas)方式增加锁资源//因为是共享锁,且没有所有者的概念,所以可以一个线程多次释放,//每次释放都会锁资源+1,甚至能无线多次释放,然后就能无限获取了,也就是卡bug了//如下所示:信号量最初资源容量限制为2,但是因为没有锁所有者的概念以及上限检测//所以直接release(100)即增加100个令牌,这样就能获取102个令牌而不会阻塞// Semaphore sem=new java.util.concurrent.Semaphore(2);// sem.release(100);// for(int i=0;i<102;i++){// sem.acquire();// }protected final boolean tryReleaseShared(int releases) {for (;;) {//读取锁资源状态int current = getState();//计算更新后的锁资源量int next = current + releases;if (next < current) throw new Error("Maximum permit count exceeded");//cas方式更新锁资源状态if (compareAndSetState(current, next))return true;//走到这里则进入下一轮循环重试}}//扣减锁资源,也是通过do{}while(!CAS)方式更新final void reducePermits(int reductions) {for (;;) {int current = getState();int next = current - reductions;if (next > current) throw new Error("Permit count underflow");if (compareAndSetState(current, next))return;}}//清空锁资源。就是把state设置为0,也是通过do{}while(!CAS)方式更新final int drainPermits() {for (;;) {int current = getState();if (current == 0 || compareAndSetState(current, 0))return current;}}}static final class NonfairSync extends Sync {private static final long serialVersionUID = -2694183684443567898L;NonfairSync(int permits) {super(permits);}//非公平方式获取锁资源:就是如果有锁资源剩余容量大于0就允许立即获得锁而无需入aqs队列排队protected int tryAcquireShared(int acquires) {return nonfairTryAcquireShared(acquires);}}static final class FairSync extends Sync {private static final long serialVersionUID = 2014338818796000944L;FairSync(int permits) {super(permits);}//公平方式获取锁资源:先来先服务的原则。//也就是说只要aqs队列不为空则说明在本线程之前有其他线程已经在排队了//公平的原则就是先来先服务,所以这里就直接返回false表示获取锁失败//一旦tryAcquireShared返回失败,则aqs会把该节点丢到aqs list的最末尾protected int tryAcquireShared(int acquires) {for (;;) {//判断是有在此之前有其他线程等待获取锁资源(即信号量)if (hasQueuedPredecessors())//如果有则返回false表获取锁资源失败return -1;//如果在此之前没有其他线程等待获取锁资源(即信号量)//则通过do{}while(!CAS)扣减锁资源int available = getState();int remaining = available - acquires;if (remaining < 0 ||compareAndSetState(available, remaining))return remaining;}}}public Semaphore(int permits) {sync = new NonfairSync(permits);}public Semaphore(int permits, boolean fair) {sync = fair ? new FairSync(permits) : new NonfairSync(permits);}//下面的函数都输对sync的一个简单封装,所以下面的函数就没注释了,一眼就能看明白public void acquire() throws InterruptedException {sync.acquireSharedInterruptibly(1);}public void acquireUninterruptibly() {sync.acquireShared(1);}public boolean tryAcquire() {return sync.nonfairTryAcquireShared(1) >= 0;}public boolean tryAcquire(long timeout, TimeUnit unit)throws InterruptedException {return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));}public void release() {sync.releaseShared(1);}public void acquire(int permits) throws InterruptedException {if (permits < 0) throw new IllegalArgumentException();sync.acquireSharedInterruptibly(permits);}public void acquireUninterruptibly(int permits) {if (permits < 0) throw new IllegalArgumentException();sync.acquireShared(permits);}public boolean tryAcquire(int permits) {if (permits < 0) throw new IllegalArgumentException();return sync.nonfairTryAcquireShared(permits) >= 0;}public boolean tryAcquire(int permits, long timeout, TimeUnit unit)throws InterruptedException {if (permits < 0) throw new IllegalArgumentException();return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));}public void release(int permits) {if (permits < 0) throw new IllegalArgumentException();sync.releaseShared(permits);}public int availablePermits() {return sync.getPermits();}public int drainPermits() {return sync.drainPermits();}protected void reducePermits(int reduction) {if (reduction < 0) throw new IllegalArgumentException();sync.reducePermits(reduction);}public boolean isFair() {return sync instanceof FairSync;}public final boolean hasQueuedThreads() {return sync.hasQueuedThreads();}public final int getQueueLength() {return sync.getQueueLength();}protected Collection<Thread> getQueuedThreads() {return sync.getQueuedThreads();}public String toString() {return super.toString() + "[Permits = " + sync.getPermits() + "]";}
}相关文章:
javalock(四)AQS派生类之Semphore逐行注释
简单概括: Semphore是一把共享锁(即读锁),即实现了AQS的tryAcquireShared&&tryReleaseShared函数Semphore的逻辑是这样: 创建semphore的时候会初始化一个锁容量即permits,即最多同时允许permits个…...
【C语言】头文件”“和<>的详解
前言 作者在刚开始学C语言的时候,都是用的< >去引用头文件,但在学习STM32的时候发现,程序中大量使用" "去引用双引号。 那么二者有什么区别呢? 无论使用哪种方式,头文件的目的都是为了引用你需要的文件供你编程使…...
Elasticsearch:什么是信息检索?
信息检索定义 信息检索 (IR) 是一种有助于从大量非结构化或半结构化数据中有效、高效地检索相关信息的过程。信息(IR)检索系统有助于搜索、定位和呈现与用户的搜索查询或信息需求相匹配的信息。 作为信息访问的主要形式,信息检索是每天使用…...
Spark-Streaming容错语义
一、背景 为了理解Spark Streaming提供的语义,我们先回顾西Spark RDD的基本容错语义学。 RDD是一个不可变的、确定性可重新计算的分布式数据集。每个RDD都记住在容错输入数据集上用于创建它的确定性操作的沿袭。如果RDD的任何分区由于工作节点故障而丢失ÿ…...
2024年12月陪玩系统-仿东郊到家约玩系统是一种新兴的线上预约线下社交、陪伴系统分享-优雅草央千澈-附带搭建教程
2024年12月陪玩系统-仿东郊到家约玩系统是一种新兴的线上预约线下社交、陪伴系统分享-优雅草央千澈-附带搭建教程 产品介绍 仿东郊到家约玩系统是一种新兴的线上预约,线下社交、陪伴、助娱、助攻、分享、解答、指导等服务模式,范围涉及电竞、运动、音乐…...
GUI07-学工具栏,懂MVC
MVC模式,是天底下编写GUI程序最为经典、实效的一种软件架构模式。当一个人学完菜单栏、开始学习工具栏时,就是他的一生中,最适合开始认识 MVC 模式的好时机之一。这节将安排您学习: Model-View-Controller 模式如何创建工具栏以及…...
【进程篇】04.进程的状态与优先级
一、进程的状态 1.1 进程的状态 1.1.1 并行与并发 • 并行: 多个进程在多个CPU下分别,同时进行运行 • 并发: 多个进程在一个CPU下采用进程切换的方式,在一个时间片内,让多个进程都得以推进 1.1.2 时间片的概念 LInux/windows这些民用级别…...
ElasticSearch 数据聚合与运算
1、数据聚合 聚合(aggregations)可以让我们极其方便的实现数据的统计、分析和运算。实现这些统计功能的比数据库的 SQL 要方便的多,而且查询速度非常快,可以实现近实时搜索效果。 注意: 参加聚合的字段必须是 keywor…...
科研学习|论文解读——智能体最新研究进展
从2024-12-13到2024-12-18的45篇文章中精选出5篇优秀的工作分享 Can Modern LLMs Act as Agent Cores in Radiology~Environments? Achieving Collective Welfare in Multi-Agent Reinforcement Learning via Suggestion Sharing A systematic review of norm emergence in …...
面试小札:Java后端闪电五连鞭_8
1. Kafka消息模型及其组成部分 - 消息(Message):是Kafka中最基本的数据单元。消息包含一个键(key)、一个值(value)和一个时间戳(timestamp)。键可以用于对消息进行分区等…...
java error(2)保存时间带时分秒,回显时分秒变成00:00:00
超简单,顺带记录一下 1.入参实体类上使用注释:JsonFormat(pattern “yyyy-MM-dd”) 导致舍弃了 时分秒的部分。 2.数据库字段对应的类型是 date。date就是日期,日期就不带时分秒。 3.返参实体类使用了JsonFormat(pattern “yyyy-MM-dd”) 导…...
计算机毕业设计python+spark+hive动漫推荐系统 漫画推荐系统 漫画分析可视化大屏 漫画爬虫 漫画推荐系统 漫画爬虫 知识图谱 大数据毕设
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
数字IC后端设计实现篇之TSMC 12nm TCD cell(Dummy TCD Cell)应该怎么加?
TSMC 12nm A72项目我们需要按照foundary的要求提前在floorplan阶段加好TCD Cell。这个cell是用来做工艺校准的。这个dummy TCD Cell也可以等后续Calibre 插dummy自动插。但咱们项目要求提前在floorplan阶段就先预先规划好位置。 TSCM12nm 1P9M的metal stack结构图如下图所示。…...
(8)YOLOv6算法基本原理
一、YOLOv6 模型原理 发布日期:2022年6月 作者:美团技术团队 骨干网络:参考了 RepVGG 的设计,将重参数化能力进行补强,增强了模型结构的重参数化能力。使用了深度可分离卷积和跨阶段连接等技术,旨在提升…...
LNMP+discuz论坛
0.准备 文章目录 0.准备1.nginx2.mysql2.1 mysql82.2 mysql5.7 3.php4.测试php访问mysql5.部署 Discuz6.其他 yum源: # 没有wget,用这个 # curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo[rootlocalhost ~]#…...
在linux系统的docker中安装GitLab
一、安装GitLab: 在安装了docker之后就是下载安装GitLab了,在linux系统中输入命令:docker search gitlab就可以看到很多项目,一般安装第一个,它是英文版的,如果英文不好可以安装twang2218/gitlab-ce-zh。 …...
Python面试常见问题及答案12
问题: 请解释Python中的GIL(全局解释器锁)是什么? ○ 答案: GIL是Python解释器中的一种机制,用于确保任何时候只有一个线程在执行Python字节码。这在多线程场景下可能影响性能优化,但对于单线程…...
从0-1开发一个Vue3前端系统页面-9.博客页面布局
本节主要实现了博客首页界面的基本布局并完善了响应式布局,因为完善了响应式布局故对前面的页面布局有所改动,这里会将改动后的源码同步上传。 1.对页面头部的用户信息进行设计和美化 布局设计参考 :通常初级前端的布局会通过多个div划分区域…...
[手机Linux] 六,ubuntu18.04私有网盘(NextCloud)安装
一,LNMP介绍 LNMP一键安装包是一个用Linux Shell编写的可以为CentOS/RHEL/Fedora/Debian/Ubuntu/Raspbian/Deepin/Alibaba/Amazon/Mint/Oracle/Rocky/Alma/Kali/UOS/银河麒麟/openEuler/Anolis OS Linux VPS或独立主机安装LNMP(Nginx/MySQL/PHP)、LNMPA(Nginx/MySQ…...
白话java设计模式
创建模式 单例模式(Singleton Pattern): 就是一次创建多次使用,它的对象不会重复创建,可以全局来共享状态。 工厂模式(Factory Method Pattern): 可以通过接口来进行实例化创建&a…...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
