当前位置: 首页 > news >正文

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逐行注释

简单概括&#xff1a; Semphore是一把共享锁&#xff08;即读锁&#xff09;&#xff0c;即实现了AQS的tryAcquireShared&&tryReleaseShared函数Semphore的逻辑是这样&#xff1a; 创建semphore的时候会初始化一个锁容量即permits&#xff0c;即最多同时允许permits个…...

【C语言】头文件”“和<>的详解

前言 作者在刚开始学C语言的时候&#xff0c;都是用的< >去引用头文件&#xff0c;但在学习STM32的时候发现&#xff0c;程序中大量使用" "去引用双引号。 那么二者有什么区别呢? 无论使用哪种方式&#xff0c;头文件的目的都是为了引用你需要的文件供你编程使…...

Elasticsearch:什么是信息检索?

信息检索定义 信息检索 (IR) 是一种有助于从大量非结构化或半结构化数据中有效、高效地检索相关信息的过程。信息&#xff08;IR&#xff09;检索系统有助于搜索、定位和呈现与用户的搜索查询或信息需求相匹配的信息。 作为信息访问的主要形式&#xff0c;信息检索是每天使用…...

Spark-Streaming容错语义

一、背景 为了理解Spark Streaming提供的语义&#xff0c;我们先回顾西Spark RDD的基本容错语义学。 RDD是一个不可变的、确定性可重新计算的分布式数据集。每个RDD都记住在容错输入数据集上用于创建它的确定性操作的沿袭。如果RDD的任何分区由于工作节点故障而丢失&#xff…...

2024年12月陪玩系统-仿东郊到家约玩系统是一种新兴的线上预约线下社交、陪伴系统分享-优雅草央千澈-附带搭建教程

2024年12月陪玩系统-仿东郊到家约玩系统是一种新兴的线上预约线下社交、陪伴系统分享-优雅草央千澈-附带搭建教程 产品介绍 仿东郊到家约玩系统是一种新兴的线上预约&#xff0c;线下社交、陪伴、助娱、助攻、分享、解答、指导等服务模式&#xff0c;范围涉及电竞、运动、音乐…...

GUI07-学工具栏,懂MVC

MVC模式&#xff0c;是天底下编写GUI程序最为经典、实效的一种软件架构模式。当一个人学完菜单栏、开始学习工具栏时&#xff0c;就是他的一生中&#xff0c;最适合开始认识 MVC 模式的好时机之一。这节将安排您学习&#xff1a; Model-View-Controller 模式如何创建工具栏以及…...

【进程篇】04.进程的状态与优先级

一、进程的状态 1.1 进程的状态 1.1.1 并行与并发 • 并行: 多个进程在多个CPU下分别&#xff0c;同时进行运行 • 并发: 多个进程在一个CPU下采用进程切换的方式&#xff0c;在一个时间片内&#xff0c;让多个进程都得以推进 1.1.2 时间片的概念 LInux/windows这些民用级别…...

ElasticSearch 数据聚合与运算

1、数据聚合 聚合&#xff08;aggregations&#xff09;可以让我们极其方便的实现数据的统计、分析和运算。实现这些统计功能的比数据库的 SQL 要方便的多&#xff0c;而且查询速度非常快&#xff0c;可以实现近实时搜索效果。 注意&#xff1a; 参加聚合的字段必须是 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消息模型及其组成部分 - 消息&#xff08;Message&#xff09;&#xff1a;是Kafka中最基本的数据单元。消息包含一个键&#xff08;key&#xff09;、一个值&#xff08;value&#xff09;和一个时间戳&#xff08;timestamp&#xff09;。键可以用于对消息进行分区等…...

java error(2)保存时间带时分秒,回显时分秒变成00:00:00

超简单&#xff0c;顺带记录一下 1.入参实体类上使用注释&#xff1a;JsonFormat(pattern “yyyy-MM-dd”) 导致舍弃了 时分秒的部分。 2.数据库字段对应的类型是 date。date就是日期&#xff0c;日期就不带时分秒。 3.返参实体类使用了JsonFormat(pattern “yyyy-MM-dd”) 导…...

计算机毕业设计python+spark+hive动漫推荐系统 漫画推荐系统 漫画分析可视化大屏 漫画爬虫 漫画推荐系统 漫画爬虫 知识图谱 大数据毕设

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;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 模型原理 发布日期&#xff1a;2022年6月 作者&#xff1a;美团技术团队 骨干网络&#xff1a;参考了 RepVGG 的设计&#xff0c;将重参数化能力进行补强&#xff0c;增强了模型结构的重参数化能力。使用了深度可分离卷积和跨阶段连接等技术&#xff0c;旨在提升…...

LNMP+discuz论坛

0.准备 文章目录 0.准备1.nginx2.mysql2.1 mysql82.2 mysql5.7 3.php4.测试php访问mysql5.部署 Discuz6.其他 yum源&#xff1a; # 没有wget&#xff0c;用这个 # curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo[rootlocalhost ~]#…...

在linux系统的docker中安装GitLab

一、安装GitLab&#xff1a; 在安装了docker之后就是下载安装GitLab了&#xff0c;在linux系统中输入命令&#xff1a;docker search gitlab就可以看到很多项目&#xff0c;一般安装第一个&#xff0c;它是英文版的&#xff0c;如果英文不好可以安装twang2218/gitlab-ce-zh。 …...

Python面试常见问题及答案12

问题&#xff1a; 请解释Python中的GIL&#xff08;全局解释器锁&#xff09;是什么&#xff1f; ○ 答案&#xff1a; GIL是Python解释器中的一种机制&#xff0c;用于确保任何时候只有一个线程在执行Python字节码。这在多线程场景下可能影响性能优化&#xff0c;但对于单线程…...

从0-1开发一个Vue3前端系统页面-9.博客页面布局

本节主要实现了博客首页界面的基本布局并完善了响应式布局&#xff0c;因为完善了响应式布局故对前面的页面布局有所改动&#xff0c;这里会将改动后的源码同步上传。 1.对页面头部的用户信息进行设计和美化 布局设计参考 &#xff1a;通常初级前端的布局会通过多个div划分区域…...

[手机Linux] 六,ubuntu18.04私有网盘(NextCloud)安装

一&#xff0c;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设计模式

创建模式 单例模式&#xff08;Singleton Pattern&#xff09;&#xff1a; 就是一次创建多次使用&#xff0c;它的对象不会重复创建&#xff0c;可以全局来共享状态。 工厂模式&#xff08;Factory Method Pattern&#xff09;&#xff1a; 可以通过接口来进行实例化创建&a…...

创业团队如何利用Taotoken以更低成本快速验证AI产品创意

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 创业团队如何利用Taotoken以更低成本快速验证AI产品创意 对于资源有限的创业团队而言&#xff0c;在产品原型阶段验证AI创意的可行…...

Tessent OCC时钟控制器配置避坑指南:如何与现有时钟门控单元协同工作

Tessent OCC时钟控制器与现有门控单元协同设计实战指南 在28nm以下工艺节点的复杂SoC设计中&#xff0c;时钟域交叉&#xff08;CDC&#xff09;问题已成为影响测试覆盖率和良率提升的关键瓶颈。据统计&#xff0c;采用传统手动集成方法的项目平均需要花费23%的DFT工时用于解决…...

高危场所专用防爆门 符合建筑消防标准

在化工车间、危险品仓库、油气厂区、锅炉房、粉尘车间等高危作业场所&#xff0c;爆炸、明火、冲击波隐患时刻存在&#xff0c;普通门窗无法起到安全防护作用&#xff0c;高危场所专用防爆门成为场地安防必备设施。 这款专业防爆门严格遵循国家建筑消防规范生产制造&#xff0…...

ROFL-Player:英雄联盟回放时光机,一键穿越所有版本

ROFL-Player&#xff1a;英雄联盟回放时光机&#xff0c;一键穿越所有版本 【免费下载链接】ROFL-Player (No longer supported) One stop shop utility for viewing League of Legends replays! 项目地址: https://gitcode.com/gh_mirrors/ro/ROFL-Player 还在为英雄联…...

Pinia Colada:革命性Vue数据获取层的完整入门指南

Pinia Colada&#xff1a;革命性Vue数据获取层的完整入门指南 【免费下载链接】pinia-colada &#x1f379; The smart data fetching layer for Vue 项目地址: https://gitcode.com/gh_mirrors/pi/pinia-colada Pinia Colada是Vue生态系统中一款革命性的数据获取层解决…...

为什么7-Zip-zstd让我的压缩效率提升了3倍?

为什么7-Zip-zstd让我的压缩效率提升了3倍&#xff1f; 【免费下载链接】7-Zip-zstd 7-Zip with support for Brotli, Fast-LZMA2, Lizard, LZ4, LZ5 and Zstandard 项目地址: https://gitcode.com/gh_mirrors/7z/7-Zip-zstd 你是否曾经面对一个巨大的项目备份文件&…...

从GPS模块到地图显示:手把手教你用Python解析NMEA-0183协议数据

从GPS模块到地图显示&#xff1a;Python实战NMEA-0183协议解析全流程 当你第一次将GPS模块连接到电脑&#xff0c;看到串口终端不断刷新的$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47这类神秘代码时&#xff0c;是否感到无从下手&#xff1f;本文将带你…...

AI编程助手Composer插件:无缝管理PHP依赖,提升结对编程效率

1. 项目概述&#xff1a;一个为AI编程助手量身定制的Composer工具如果你和我一样&#xff0c;日常重度依赖像Aider这样的AI编程助手来提升开发效率&#xff0c;那你一定遇到过这样的场景&#xff1a;你正和AI助手热火朝天地讨论一个功能实现&#xff0c;它为你生成了一段完美的…...

SpringBoot项目快速集成Taotoken多模型API的完整教程

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 SpringBoot项目快速集成Taotoken多模型API的完整教程 对于使用SpringBoot框架的Java开发者而言&#xff0c;接入不同的大模型服务通…...

libhv实战:手把手教你用C++写一个带自动重连的WebSocket客户端(附避坑指南)

libhv实战&#xff1a;构建高可靠WebSocket客户端的工程化实践 在实时数据采集和监控系统中&#xff0c;WebSocket客户端的稳定性直接决定了业务连续性。当网络出现闪断、服务端重启或负载波动时&#xff0c;简单的连接断开可能导致关键数据丢失。libhv作为高性能网络库&#x…...