Redis实现分布式锁源码分析
为什么使用分布式锁
单机环境并发时,使用synchronized或lock接口可以保证线程安全,但它们是jvm层面的锁,分布式环境并发时,100个并发的线程可能来自10个服务节点,那就是跨jvm了。
简单分布式锁实现
SETNX
格式:setnx key value
当且仅当key不存在时,key能设置成功并返回1,否则返回0。
SETNX即SET if Not eXists 如果不存在。
SETNX存在的问题
高并发场景下,有可能存在key自动过期了,加锁的线程还未执行完成的情况。此时线程2加锁进来了,且刚好线程1执行完了,线程1会把线程2刚刚创建的锁删掉,导致后面进来了更多的线程。【自己加的锁被别人删除了】
解决方案:给每个加锁的key生成一个唯一的UUID作为value,删除之前,从redis拿出来的UUID与当前线程一致才能删除key。
然而finally依然存在问题,因为释放锁的代码不是原子操作。【超时零界点】,在判断uuid相同后,且还未删除key前,此时key超时了,其他线程加锁成功,当前线程执行delete命令时,删除的依然是其他线程加的锁。
以上问题均是由于锁的时间不够长导致,接下来的解决方案是【锁续命】
锁续命
原理:线程1加锁成功后,再创建一个线程,使用定时任务来监控锁剩余时间。定时任务执行的周期必须小于锁的超时时间。比如锁超时时间默认设置为30秒,那么该线程每10秒执行一次,给锁重新设置超时时间为30秒, 保证主线程删除锁时,是自己加的锁。如果主线程已释放锁,子线程执行定时任务时会先判断主线程加的key是否还存在。 目前市面上已有成熟的解决方案,如redisson,它适用于分布式各种场景。参考redisson帮助文档
Redisson续命锁流程
引入redisson的依赖包
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.27.2</version>
</dependency>
创建一个Redisson的bean注册到Spring容器中
//获取锁对象
RLock redissonLock = redisson.getLock(lockKey);
//加分布式锁
redissonLock.lock();
........
//解锁
redissonLock.unlock();
Redisson加锁源码
底层是基于lua脚本实现,它能保证原子性。因为Redis服务端执行命令是单线程的,读到这一块lua代码会将它当成一个整体执行完,再去执行下一条命令。
第一步:通过lua脚本加锁成后,返回null,加锁失败返回锁剩余时间。
hset key field value
通过hash结构设置field为UUID+线程ID
,value是1,表示重入次数。 key是构建锁时传入的redisson.getLock(lockKey);
锁超时时间默认是30秒。
第二步:看门狗机制给锁续命
Future模式异步执行lua脚本加锁,加锁成功后回调Future的监听器获取加锁结果。 加锁的lua脚本执行成功后返回null,则进入scheduleExpireRenewal()
方法定时的给锁重置超时时间。
创建一个TimeTask延时任务,10秒后才执行run()方法,lua脚本判断锁存在则重设锁的超时时间为30秒。它同样是使用的Future模式,下面添加了一个监听,重置结束后,会回调监听器,监听器拿到结果再回调scheduleExpireRenewal()
方法本身。
第三步:加锁失败的线程自旋等待
- 加锁失败后,先订阅该key的channel通道消息,类似于一个队列或topic,当锁在过期之前释放了,需要唤醒等待的线程竞争锁。
- 进入while(true)自旋加锁。先尝试一次加锁,成功则退出循环,失败则获取Semaphore调用tryAcquire()等待ttl秒后,重新进入while(true)尝试获取锁。如果1000个线程同时结束等待,就会一起抢锁,所以该锁是非公平锁。
第四步:释放锁时,发布该key的channel消息,通知等待的线程竞争锁。
一旦channel中有消息后,会执行LockPubSub.onMessage()
方法,获取一个Semaphora信号量释放等待的线程,让他们竞争锁。
总结:redisson的架构设计涉及到Future,自旋锁,看门狗机制,发布订阅,lua脚本,semaphore等技术。
它的lock()接口实现的是非公平锁。tryAcquire()加锁成功后,继续执行业务代码。其他线程拿锁时返回锁剩余的时间ttl,判断ttl大于0,则使用Semaphore.getLatch().tryAcquire()
,等到超时时间结束后再去抢锁。如果ttl还没有变为0,此时锁已释放,主线程会向指定的channel发送一条消息,等待的线程会订阅这个消息LockPubSub.onMessage()
,拿到释放锁的消息后调用Semaphore.getLatch().release()
,唤醒阻塞的线程立刻抢锁。
主线程给锁续命使用的是Future机制,异步开启了一个线程,每隔10秒嵌套调用重设锁时间的方法。
lua脚本
相关文章:

Redis实现分布式锁源码分析
为什么使用分布式锁 单机环境并发时,使用synchronized或lock接口可以保证线程安全,但它们是jvm层面的锁,分布式环境并发时,100个并发的线程可能来自10个服务节点,那就是跨jvm了。 简单分布式锁实现 SETNX 格式&…...
SCI 图像处理期刊
引用 一区 1. IEEE TRANSACTIONS ON PATTERN ANALYSIS AND MACHINE INTELLIGENCE 顶刊:是 出版商:IEEE 2. IEEE Transactions on Multimedia 顶刊:是 出版商:IEEE 3. Information Fusion 顶刊:是 出版商:ELSEVIER 4.IEEE TRANSACTIONS ON IMAGE PROCESSING 顶刊:是 出版商:I…...

数据结构-红黑树
1.容器 容器用于容纳元素集合,并对元素集合进行管理和维护. 传统意义上的管理和维护就是:增,删,改,查. 我们分析每种类型容器时,主要分析其增,删,改ÿ…...

双指针、bfs与图论
1238. 日志统计 - AcWing题库 import java.util.*;class PII implements Comparable<PII>{int x, y;public PII(int x, int y){this.x x;this.y y;}public int compareTo(PII o){return Integer.compare(x, o.x);} }public class Main{static int N 100010, D, K;st…...

RabbitMQ高级-高级特性
1.消息可靠性传递 在使用RabbitMQ的时候,作为消息发送方希望杜绝任何消息丢失或者投递失败场景。RabbitMQ为我们提供了两种方式来控制消息的投递可靠性模式 1.confirm 确认模式 确认模式是由exchange决定的 2.return 退回模式 回退模式是由routing…...

Word粘贴时出现“运行时错误53,文件未找到:MathPage.WLL“的解决方案
在安装完MathType后,打开word复制粘贴时报错“运行时错误53,文件未找到:MathPage.WLL” 首先确定自己电脑的位数(这里默认32位) 右击MathType桌面图标,点击“打开文件所在位置”, 然后分别找到MathPage.W…...
html元素基本使用
前言 大家好,我是jiantaoyab,第一次学习前端的html,写一篇笔记总结常用的元素 语义化 例如只要是 不管字体的大小是怎么样,有没有加粗都是标题,元素显示到页面中的效果应该由css决定,这就是语义化。 文…...

PHP+golang开源办公系统CRM管理系统
基于ThinkPHP6 Layui MySQL的企业办公系统。集成系统设置、人事管理、消息管理、审批管理、日常办公、客户管理、合同管理、项目管理、财务管理、电销接口集成、在线签章等模块。系统简约,易于功能扩展,方便二次开发。 服务器运行环境要求 PHP > 7.…...
smartmontools-5.43交叉编译Smartctl
嵌入式系统的sata盘经常故障,需要使用smatctl工具监控和诊断sata故障。 1. 从网上下载开源smartmontools-5.43包。 2. 修改makefile进行交叉编译。 由于软件包中已经包含Makefile.am,Makefile.in。直接运行 automake --add-missing 生成Makefile。 3.…...

idea找不到或无法加载主类
前言 今天在运行项目的时候突然出了这样一个错误:IDEA 错误 找不到或无法加载主类,相信只要是用过IDEA的朋友都 遇到过它吧,但是每次遇到都是一顿焦头烂额、抓耳挠腮、急赤白咧!咋整呢?听我给你吹~ 瞧我这张嘴~ 问题报错 找不…...

2.二进制的方式读写文件
文章目录 写入文件代码运行结果 读出文件代码运行结果 文件打开模式标记(查表) 写入文件 ------写文件一共五步:------ 第一步:包含头文件 第二步:创建流对象 第三步:指定方式打开文件 第四步:…...
Seata的详细解释
什么是seata Seata(Simple Extensible Autonomous Transaction Architecture)是一个开源的分布式事务解决方案。它是由阿里巴巴集团开发的,旨在解决分布式系统中的事务一致性问题。 Seata提供了一种简单易用的方式来实现跨多个数据库和服务的…...
JS手写实现洋葱圈模型
解释洋葱圈模型: 当我们执行第一个中间件时,首先输出1,然后调用next(),那么此时它会等第二个中间件执行完毕才会继续执行第一个中间件。然后执行第二个中间件,输出3,调用next(),执行第三中间件…...

3.Windows下安装MongoDB和Compass教程
Windows下安装MongoDB 总体体验下来,,要比MySQL的安装简单了许多,没有过多的配置,直接就上手了! 1、下载 进入官方的下载页面https://www.mongodb.com/try/download/community,如下选择,我选…...
go反射实战
文章目录 demo1 数据类型判断demo2 打印任意类型数据 demo1 数据类型判断 使用reflect.TypeOf()方法打印go中数据类型,可参考go官方API文档;使用格式化参数%T也能打印数据类型。 package mainimport "fmt" import "reflect" import "io&…...

Docker 中 MySQL 的部署与管理
目录 一、Docker 中部署 MySQL1.1 部署 MySQL1.2 进入容器并创建数据库1.3 Navicat 可视化工具连接 二、可能存在的问题2.1 1130 - Host ‘172.17.0.1‘ is not allowed to connect to this MySQL server 参考资料 一、Docker 中部署 MySQL 1.1 部署 MySQL 首先,从…...
基础练习题之函数
前言 这些题目来自与一些刷题网站,以及c primer plus,继续练习 第一题 给你一个数,让他进行巴啦啦能量,沙鲁沙鲁,小魔仙大变身,如果进行变身的数不满足条件的话,就继续让他变身。。。直到满足条件为止。 巴啦啦能量…...

Java NIO浅析
NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接、I/O处理问题…...
数据挖掘与大数据的结合
随着大数据技术的不断发展和普及,数据挖掘在大数据环境下的应用也变得更加广泛和深入。以下将探讨大数据技术对数据挖掘的影响,以及如何利用大数据技术处理海量数据并进行有效的数据挖掘,同时分析大数据环境下的数据挖掘挑战和解决方案。 1.…...
分布式链路追踪(一)SkyWalking(2)使用
一、使用方法 1、简介 agent探针可以让我们不修改代码的情况下,对Java应用上使用到的组件进行动态监控,获取运行数据发送到OAP上进行统计和存储。agent探针在Java使用中是使用Java agent技术实现。不需要更改任何代码,Java agent会通过虚拟…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...