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

大浪网站建设/企业培训课程

大浪网站建设,企业培训课程,店铺代运营服务,有做微信婚介网站的吗1 分布式锁 Java锁能保证一个JVM进程里多个线程交替使用资源。而分布式锁保证多个JVM进程有序交替使用资源,保证数据的完整性和一致性。 分布式锁要求 互斥。一个资源在某个时刻只能被一个线程访问。避免死锁。避免某个线程异常情况不释放资源,造成死锁…

1 分布式锁

Java锁能保证一个JVM进程里多个线程交替使用资源。而分布式锁保证多个JVM进程有序交替使用资源,保证数据的完整性和一致性。
分布式锁要求

  1. 互斥。一个资源在某个时刻只能被一个线程访问。
  2. 避免死锁。避免某个线程异常情况不释放资源,造成死锁。
  3. 可重入。
  4. 高可用。高性能。
  5. 非阻塞,没获取到锁直接返回失败。

2 实现

1 lua脚本

为了实现redis操作的原子性,使用lua脚本。为了方便改脚本,将脚本单独写在文件里。

-- 加锁脚本
if redis.call('setnx', KEYS[1], ARGV[1]) == 1 thenredis.call('pexpire', KEYS[1], ARGV[2]);return true;
elsereturn false;
end-- 解锁脚本
if redis.call('get', KEYS[1]) == ARGV[1] thenredis.call('del', KEYS[1]);return true;
elsereturn false;
end-- 更新锁脚本
if redis.call('get', KEYS[1]) == ARGV[1] thenredis.call('pexpire', KEYS[1], ARGV[2]);-- pexpire与expire的区别是:pexpire毫秒级,expire秒级return true;
elsereturn false;
end

将脚本装在Springboot容器管理的bean里。

@Configuration
public class RedisConfig {@Bean("lock")public RedisScript<Boolean> lockRedisScript() {DefaultRedisScript redisScript = new DefaultRedisScript<>();redisScript.setResultType(Boolean.class);redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("/ratelimit/lock.lua")));return redisScript;}@Bean("unlock")public RedisScript<Boolean> unlockRedisScript() {DefaultRedisScript redisScript = new DefaultRedisScript<>();redisScript.setResultType(Boolean.class);redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("/ratelimit/unlock.lua")));return redisScript;}@Bean("refresh")public RedisScript<Boolean> refreshRedisScript() {DefaultRedisScript redisScript = new DefaultRedisScript<>();redisScript.setResultType(Boolean.class);redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("/ratelimit/refresh.lua")));return redisScript;}
}

redis分布式锁业务类

@Service
public class LockService {private static final long LOCK_EXPIRE = 30_000;private static final Logger LOGGER = LoggerFactory.getLogger(LockService.class);@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Autowired@Qualifier("lock")private RedisScript<Boolean> lockScript;@Autowired@Qualifier("unlock")private RedisScript<Boolean> unlockScript;@Autowired@Qualifier("refresh")private RedisScript<Boolean> refreshScript;public boolean lock(String key, String value) {boolean res = redisTemplate.execute(lockScript, List.of(key), value, LOCK_EXPIRE);if (res == false) {return false;}refresh(key, value);LOGGER.info("lock, key: {}, value: {}, res: {}", key, value, res);return res;}public boolean unlock(String key, String value) {Boolean res = redisTemplate.execute(unlockScript, List.of(key), value);LOGGER.info("unlock, key: {}, value: {}, res: {}", key, value, res);return res != null && Boolean.TRUE.equals(res);}private void refresh(String key, String value) {Thread t = new Thread(() -> {while (true) {redisTemplate.execute(refreshScript, List.of(key), value, LOCK_EXPIRE);try {Thread.sleep(LOCK_EXPIRE / 2);} catch (InterruptedException e) {e.printStackTrace();}LOGGER.info("refresh, current time: {}, key: {}, value: {}", System.currentTimeMillis(), key, value);}});t.setDaemon(true); // 守护线程t.start();}
}

测试类

@SpringBootTest(classes = DemoApplication.class)
public class LockServiceTest {@Autowiredprivate LockService service;private int count = 0;@Testpublic void test() throws Exception {List<CompletableFuture<Void>> taskList = new ArrayList<>();for (int threadIndex = 0; threadIndex < 10; threadIndex++) {CompletableFuture<Void> task = CompletableFuture.runAsync(() -> addCount());taskList.add(task);}CompletableFuture.allOf(taskList.toArray(new CompletableFuture[0])).join();}public void addCount() {String id = UUID.randomUUID().toString().replace("-", "");boolean tryLock = service.lock("account", id);while (!tryLock) {tryLock = service.lock("account", id);}for (int i = 0; i < 10_000; i++) {count++;}try {Thread.sleep(100_000);} catch (Exception e) {System.out.println(e);}for (int i = 0; i < 3; i++) {boolean releaseLock = service.unlock("account", id);if (releaseLock) {break;}}}
}

3 存在的问题

这个分布式锁实现了互斥,redis键映射资源,如果存在键,则资源正被某个线程持有。如果不存在键,则资源空闲。
避免死锁,靠的是设置reds键的过期时间,同时开启守护线程动态延长redis键的过期时间,直到该线程任务完结。
高性能。redis是内存数据库,性能很高。同时lua脚本使得redis以原子性更新锁状态,避免多次spirngboot与redis的网络IO。
非阻塞。lock()方法没有获取到锁立即返回false,不会阻塞当前线程。

没有实现可重入和高可用。高可用需要redis集群支持。

相关文章:

springboot+redis+lua实现分布式锁

1 分布式锁 Java锁能保证一个JVM进程里多个线程交替使用资源。而分布式锁保证多个JVM进程有序交替使用资源&#xff0c;保证数据的完整性和一致性。 分布式锁要求 互斥。一个资源在某个时刻只能被一个线程访问。避免死锁。避免某个线程异常情况不释放资源&#xff0c;造成死锁…...

【Petri网导论学习笔记】Petri网导论入门学习(十一) —— 3.3 变迁发生序列与Petri网语言

目录 3.3 变迁发生序列与Petri网语言定义 3.4定义 3.5定义 3.6定理 3.5例 3.9定义 3.7例 3.10定理 3.6定理 3.7 有界Petri网泵引理推论 3.5定义 3.9定理 3.8定义 3.10定义 3.11定义 3.12定理 3.93.3 变迁发生序列与Petri网语言 对于 Petri 网进行分析的另一种方法是考察网系统…...

docker-compose文件的简介及使用

Docker Compose是Docker官方的开源项目&#xff0c;主要用于定义和运行多容器Docker应用。以下是对Docker Compose的详细介绍&#xff1a; 一、主要功能&#xff1a; 容器编排&#xff1a;Docker Compose允许用户通过一个单独的docker-compose.yml模板文件&#xff08;YAML格…...

[护网杯 2018]easy_tornado

这里有一个hint点进去看看&#xff0c;他说md5(cookie_secretmd5(filename))&#xff0c;所以我们需要获得cookie_secret的value 根据题目tornado,它可能是tornado的SSTI 这里吧filehash改为NULL. 是tornado的SSTI 输入{{handler.settings}} (settings 属性是一个字典&am…...

基于STM32的智能风扇控制系统

基于STM32的智能风扇控制系统 持续更新&#xff0c;欢迎关注!!! ** 基于STM32的智能风扇控制系统 ** 近几年&#xff0c;我国电风扇市场发展迅速&#xff0c;产品产出持续扩张&#xff0c;国家产业政策鼓励电风扇产业向高技术产品方向发展&#xff0c;国内企业新增投资项目投…...

决策树——基于乳腺癌数据集与cpu数据集实现

决策树——乳腺癌数据实现 4.1 训练决策树模型,并计算测试集的准确率 1. 读入数据 from sklearn import datasets from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import confusion_matrix …...

探索空间自相关:揭示地理数据中的隐藏模式

目录 一、什么是空间自相关&#xff1f; 类型 二、空间自相关的数学基础 空间加权矩阵 三、度量空间自相关的方法 1. 全局自相关 2. 局部自相关 四、空间自相关的实际应用 五、Python实现空间自相关分析 1. 数据准备 2. 计算莫兰指数 3. 局部自相关&#xff08;LISA 分析&…...

echarts使用示例

柱状图折线图 折柱混合&#xff1a;https://echarts.apache.org/examples/zh/editor.html?cmix-line-bar option {title:{show: true},tooltip: {trigger: axis,axisPointer: {type: cross,crossStyle: {color: #999}}},toolbox: {feature: {dataView: { show: true, readOnl…...

Flink高可用配置(HA)

从Flink架构中我们可以看到,JobManager这个组件非常重要,是中心协调器,负责任务调度和资源管理。默认情况下,每个Flink集群只有一个JobManager实例。这会产生单点故障(SPOF):如果JobManager崩溃,则无法提交新程序,正在运行的程序也会失败。通过JobManager的高可用性,…...

如何编写出色的技术文档

目录 ​编辑 1. 明确文档目的和受众 目的的重要性 了解受众 2. 收集和组织信息 信息收集的技巧 组织信息 3. 规划文档结构 结构规划的重要性 结构规划的步骤 4. 编写内容 语言和风格 内容的组织 编写技巧 5. 审阅和测试 审阅的重要性 测试的必要性 6. 版本控…...

学习日记_20241126_聚类方法(谱聚类Spectral Clustering)

前言 提醒&#xff1a; 文章内容为方便作者自己后日复习与查阅而进行的书写与发布&#xff0c;其中引用内容都会使用链接表明出处&#xff08;如有侵权问题&#xff0c;请及时联系&#xff09;。 其中内容多为一次书写&#xff0c;缺少检查与订正&#xff0c;如有问题或其他拓展…...

图书系统小案例

目前就实现了分页查询&#xff0c;修改&#xff0c;删除功能 这个小案例练习到了很多技能&#xff0c;比如前后端交互、异步请求、三层架构思想、后端连接数据库、配置文件、基础业务crud等等 感兴趣的小伙伴可以去做一个试试 准备工作 1、使用maven构建一个web工程 打开i…...

目标检测之学习路线(本科版)

以下是为一名计算机科学与技术本科大四学生整理的“目标检测”学习路线&#xff0c;结合了从基础到高级的内容&#xff0c;适合初学者逐步深入。每个阶段都有明确的学习要求、学习建议和资源推荐。 阶段一&#xff1a;基础知识学习 学习要求&#xff1a; 掌握编程语言 Pytho…...

C#调用C++ DLL方法之C++/CLI(托管C++)

托管C与C/CLI前世今生 C/CLI (C/Common Language Infrastructure) 是一种用于编写托管代码的语言扩展&#xff0c;它是为了与 .NET Framework 进行互操作而设计的。C/CLI 是 C 的一种方言&#xff0c;它引入了一些新的语法和关键字&#xff0c;以便更好地支持 .NET 类型和垃圾…...

免费搭建一个属于自己的个性化博客(Hexo+Fluid+Github)

文章目录 0.简介1. 下载安装fluid主题2. 创建文章3. 添加分类及标签3.1 创建“分类”选项3.2 创建“标签”选项4. 文章中插入图片5. 添加阅读量统计6. 添加评论功能7. 显示文章更新时间8. 为hexo添加latex支持小结参考文献0.简介 通过HEXO模板和Fluid主题搭建自己的博客,预览…...

vue3 开发利器——unplugin-auto-import

这玩意儿是干啥的&#xff1f; 还记得 Vue 3 的组合式 API 语法吗&#xff1f;如果有印象&#xff0c;那你肯定对以下代码有着刻入 DNA 般的熟悉&#xff1a; 刚开始写觉得没什么&#xff0c;但是后来渐渐发现&#xff0c;这玩意儿几乎每个页面都有啊&#xff01; 每次都要写…...

开发需求总结19-vue 根据后端返回一年的数据,过滤出符合条件数据

需求描述&#xff1a; 定义时间分界点&#xff1a;每月26号8点&#xff0c;过了26号8点则过滤出data数组中符合条件数据下个月的数据&#xff0c;否则过滤出当月数据 1.假如现在是2024年11月14日&#xff0c;那么过滤出data数组中日期都是2024-11月的数据&#xff1b; 2.假如…...

人工智能如何改变创新和创造力?

王琼工作室 输出的力量 有了GPT这样的人工智能平台&#xff0c;创新和创造力的机会在哪里&#xff1f; 我们是否有信心&#xff1a; 面对效率&#xff0c;超越效率。 把问题拓展为机会&#xff1f; 把机会拓展为价值&#xff1f; 让智能更好地和我们协作&#xff0c;走心、走…...

Github 基本使用学习笔记

1. 基本概念 1.1 一些名词 Repository&#xff08;仓库&#xff09; 用来存放代码&#xff0c;每个项目都有一个独立的仓库。 Star&#xff08;收藏&#xff09; 收藏你喜欢的项目&#xff0c;方便以后查看。 Fork&#xff08;克隆复制项目&#xff09; 复制别人的仓库&…...

群论入门笔记

群的基本定义 群由一组元素 G 和一个运算&#xff08;常用符号包括 &#xff0c;x , 或 ∗&#xff09;组成。 封闭性 对于任意两个元素 x,y∈G&#xff0c;运算 x * y 的结果仍然属于集合 G&#xff0c;即&#xff1a; ∀x,y∈G,x∗y∈G. 结合律 对于任意 a,b,c∈G&…...

2024最新python使用yt-dlp

2024最新python使用yt-dlp下载YT视频 1.获取yt的cookie1&#xff09;google浏览器下载Get cookies.txt LOCALLY插件2&#xff09;导出cookie 2.yt-dlp下载[yt-dlp的GitHub地址](https://github.com/yt-dlp/yt-dlp?tabreadme-ov-file)1&#xff09;使用Pycharm(2024.3)进行代码…...

Python + 深度学习从 0 到 1(00 / 99)

希望对你有帮助呀&#xff01;&#xff01;&#x1f49c;&#x1f49c; 如有更好理解的思路&#xff0c;欢迎大家留言补充 ~ 一起加油叭 &#x1f4a6; 欢迎关注、订阅专栏 【深度学习从 0 到 1】谢谢你的支持&#xff01; ⭐ 什么是深度学习&#xff1f; 人工智能、机器学习与…...

单点登录深入详解之设计方案总结

基于cookie的单点登录解决方案 概述 用户登录之后 , 将认证信息存储至 Cookie &#xff0c;当再次访问本服务或者访问其他应用服务时&#xff0c;直接从 Cookie 中传递认证信息&#xff0c;进行鉴权处理。 问题 1. 如何保障Cookie内用户认证信息的安全性? 第一, Cookie…...

Loadsh源码分析-forEach,eachRight,map,flatMap,flatMapDeep,flatMapDepth

处理数组array的函数已经学习完&#xff0c;接下来是collection相关的函数&#xff0c; collection指的是一组用于处理集合&#xff08;如数组或对象&#xff09;的工具函数。 lodash源码研读之forEach,forEachRight,map,flatMap,flatMapDeep,flatMapDepth 一、源码地址 GitH…...

检测到“runtimelibrary”的不匹配项: 值“mtd_staticdebug”不匹配值“mdd_dynamic”

1. 解释“runtimelibrary”不匹配错误的含义 在Visual Studio中&#xff0c;LNK2038错误表示链接器检测到项目与其依赖的库之间存在“Runtime Library”&#xff08;运行时库&#xff09;的不匹配。具体来说&#xff0c;这意味着编译项目时使用的运行时库类型与编译依赖库时使…...

go clean -modcache命令清理缓存

go clean -modcache命令用于清理Go模块的本地缓存。Go模块缓存位于$GOPATH/pkg/mod/cache目录下&#xff0c;存储了所有下载和使用的模块版本。当执行go clean -modcache时&#xff0c;这个命令会删除该目录下的所有内容&#xff0c;迫使Go在下次构建时重新下载所有依赖的模块。…...

C#结构体排序(数组)

结构体排序&#xff08;数组&#xff09; 1 示例1.1 以PointF为例展示效果1.2 运行结果展示 2实际运用2.1 创建结构体2.2 调用示例2.3 运行结果展示 1 示例 1.1 以PointF为例展示效果 private void button1_Click(object sender, EventArgs e) {Random random new Random();…...

基于边缘智能网关的机房安全监测应用

随着我国工业互联网的扎实推进&#xff0c;越来越多地区积极建设信息基础设施&#xff0c;以充沛算力支撑产业物联网的可持续发展&#xff0c;数据机房就是其中的典型代表。而且随着机房规模的扩大&#xff0c;对于机房的安全管理难题挑战也日益增加。 面向数据机房安全监测与管…...

【Jenkins】自动化部署 maven 项目笔记

文章目录 前言1. Jenkins 新增 Maven 项目2. Jenkins 配置 Github 信息3. Jenkins 清理 Workspace4. Jenkins 配置 后置Shell脚本后记 前言 目标&#xff1a;自动化部署自己的github项目 过程&#xff1a;jenkins 配置、 shell 脚本积累 相关连接 Jenkins 官方 docker 指导d…...

LeetCode 3243. Shortest Distance After Road Addition Queries I

&#x1f517; https://leetcode.com/problems/shortest-distance-after-road-addition-queries-i 题目 有 n 个城市&#xff0c;编号 0 ~ n-1&#xff0c;从城市 i 到 i1 有一条路给若干高速路&#xff0c;表明从城市 u 到 v 有一条新增的路&#xff0c;v - u > 1返回每新…...