黑马点评05分布式锁 1互斥锁和过期时间

实战篇-09.分布式锁-基本原理和不同实现方式对比_哔哩哔哩_bilibili

1.分布式锁

因为jvm内部的sychonized锁无法在不同jvm之间共享锁监视器,所以需要一个jvm外部的锁来共享。

2.redis setnx互斥锁

加锁解锁即可

2.1不释放锁可能死锁

redis 的setnx不会自动释放锁,要是加锁后服务宕机,锁得不到释放可能死锁。

所以需要给锁加过期时间。

2.2保证加锁和过期时间的原子性

用set + 参数的方式同时设置锁和过期时间,保证不会因为过期时间没来及设置就宕机导致死锁

最终版本 :

到此为止基本完成了分布式锁,但是还可以加以改进

2.3.其他线程失败后是否阻塞?

一般用非阻塞式,阻塞式浪费cpu而且实现麻烦。

阻塞式就是发现别人用锁,就一直等待。

非阻塞式就是别人拿锁我就返回。

3.实现redis set nx分布式锁 

 

3.1获取redis分布式锁

private String name; //业务名字private StringRedisTemplate stringRedisTemplate;private static final String KEY_PREFIX = "lock:"; //规范名字private static final String ID_PREFIX = UUID.randomUUID() + "-";private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {this.name = name;this.stringRedisTemplate = stringRedisTemplate;}@Overridepublic boolean tryLock(long timeoutSec) {//获取线程标示String threadId = ID_PREFIX + Thread.currentThread().getId();//获取锁 set  key value  NX  EX 过期时间Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success);  //防拆箱空指针}

3.2释放redis分布式锁

4.业务使用redis分布式锁

在订单创建业务那里把sychnoized锁改成自己实现的分布式锁(获取+解锁)

5.服务阻塞导致分布式锁误删问题(判断锁的线程标识)

业务1阻塞时间太长,导致锁过期自动删除,

5.1解决方式:判断线程标识符是否是自己的,需要一个全局唯一线程标识符

 每个jvm内部的线程号是一种递增的数字,但是不同的jvm之间线程号可能冲突,所以需要找一种方法 区分不仅jvm内部而且jvm之间的线程。

uuid是一种唯一识别码,能保证不同的服务(jvm)的uuid一定不一样。

所以用 uuid + jvm内部线程id的方式来唯一标识所有jvm中的线程

小科普:通用唯一标识码UUID的介绍及使用 - 知乎 (zhihu.com)

5.1.1实现(加锁和释放时加上了唯一线程标识判断)

5.2另一种误删问题(判断完之后阻塞丢锁,后面又释放,需要保证线程id和释放锁的原子性)

实战篇-15.分布式锁-Lua脚本解决多条命令原子性问题_哔哩哔哩_bilibili

5.2.1保证原子性--lua脚本

调用redis提供的call函数,传入redis命令参数

为了传参而把参数位留空后:

 5.2.2java调用lua脚本

 提前读取好lua文件,避免频繁读取,等会调用。

为了维持 释放锁时 判断线程id和释放锁操作的原子性,重写unlcok方法

6.最终该类代码

package com.hmdp.utils;import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;public class SimpleRedisLock implements ILock {private String name; //业务名字private StringRedisTemplate stringRedisTemplate;private static final String KEY_PREFIX = "lock:"; //规范名字private static final String ID_PREFIX = UUID.randomUUID() + "-";private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;static {UNLOCK_SCRIPT = new DefaultRedisScript<>();UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));UNLOCK_SCRIPT.setResultType(Long.class);}public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {this.name = name;this.stringRedisTemplate = stringRedisTemplate;}@Overridepublic boolean tryLock(long timeoutSec) {//获取线程标示String threadId = ID_PREFIX + Thread.currentThread().getId();//获取锁 set  key value  NX  EX 过期时间Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success);  //防拆箱空指针}@Overridepublic void unlock() {//调用lua脚本stringRedisTemplate.execute(UNLOCK_SCRIPT,Collections.singletonList(KEY_PREFIX + name),ID_PREFIX + Thread.currentThread().getId());}/**@Overridepublic void unLock() {//获取线程标识String threadId = ID_PREFIX + Thread.currentThread().getId();//获取锁中的标识String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + name);//判断标识是否一致if (threadId.equals(id)) {//释放锁stringRedisTemplate.delete(KEY_PREFIX + name);}}* */
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Crow:黑魔法 添加路由2 new_rule_tagged实现模板参数的绑定

Crow添加路由的定义: #define CROW_ROUTE(app, url) app.template route<crow::black_magic::get_parameter_tag(url)>(url) Crow:黑魔法get_parameter_tag-CSDN博客 介绍了get_parameter_tag的作用 route的定义为: auto route(std::string&& rule) -> …

微信小程序生成二维码海报并分享

背景&#xff1a;点击图标&#xff0c;生成海报后&#xff0c;点击保存相册&#xff0c;可以保存 生成海报&#xff1a;插件wxa-plugin-canvas&#xff0c;此处使用页面异步生成组件方式&#xff0c;官网地址&#xff1a;wxa-plugin-canvas - npm 二维码&#xff1a;调用后端…

用CC三维建模建出的OSGB格式,用模方打不开,显示该路径包含OSGB瓦块数量0,是什么原因?

答&#xff1a;模方只识别tile命名的模型文件&#xff0c;此模型是不分块输出&#xff0c;要平面切块重新跑。 模方是一款针对实景三维模型的冗余碎片、水面残缺、道路不平、标牌破损、纹理拉伸模糊等共性问题研发的实景三维模型修复编辑软件。模方4.1新增自动单体化建模功能&…

巴贝拉葡萄酒是单一品种还是混合品种制成的?

大多数巴贝拉葡萄酒都是由单一的巴贝拉葡萄品种制成的&#xff0c;许多意大利葡萄酒商开始尝试在巴贝拉葡萄酒中加入其它葡萄品种&#xff0c;其中两个最受欢迎的意大利品种是皮埃蒙特的巴贝拉德阿尔巴和达斯蒂。和朋友在一家意大利餐厅吃饭&#xff0c;被酒单吓到了&#xff1…

24. 常用shell之 du - 显示目录空间使用情况 的用法和衍生用法

du&#xff08;disk usage&#xff09;是 Unix 和类 Unix 系统&#xff08;如 Linux 和 macOS&#xff09;中的一个命令&#xff0c;用于显示文件和目录的磁盘空间使用情况。与 df 命令不同&#xff0c;du 更注重于单个文件和目录的空间使用&#xff0c;而不是整个文件系统的使…

10.1Linux输入子系统介绍

输入设备介绍 鼠标、键盘、按键、触摸屏等提供输入支持的设备都属于输入设备&#xff0c;在Linux也提供了一套驱动框架“input 子系统”与之对应&#xff0c;用于抽象输入设备&#xff0c;并提供管理输入设备驱动和输入事件处理程序的功能 input 子系统 input 子系统用于管理…

GPT 魔力涌现

GPT 二、Prompt 的典型构成 角色&#xff1a;给 AI 定义一个最匹配任务的角色&#xff0c;比如&#xff1a;「你是一位软件工程师」「你是一位小学老师」指示&#xff1a;对任务进行描述上下文&#xff1a;给出与任务相关的其它背景信息&#xff08;尤其在多轮交互中&#xff…

分布式文件存储系统minio了解下

什么是minio minio 是一个基于 Apache License v2.0 开源协议的对象存储服务。非常适合于存储大容量非结构化的数据&#xff0c;例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等&#xff0c;而一个对象文件可以是任意大小。 是一种海量、安全、低成本、高可靠的云存储…

机器学习笔记 - 用于自动化检测服饰的YOLOs-Fashionpedia模型

一、安装环境 使用预训练模型和 PyTorch Lightning 来自动化产品标记过程,将大幅度提高耗时的任务的效率。 # 安装软件包 pip install torch== 2.0 .0 pip install pytorch-lightning== 2.0 .1 pip install datasets== 2.11 .0 pip install Transformers== 4.30

Map.entry用法详解

Map.entry用法详解 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;在Java编程的旅途中&#xff0c;Map.Entry是一位不可或缺的伙伴&#xff0c;为我们提供了在Map中…

Java: Random

/*** encoding: utf-8* 版权所有 2023 涂聚文有限公司* 许可信息查看&#xff1a;* 描述&#xff1a; //https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/RandomStringUtils.html* //https://commons.apache.org/pro…

#HarmonyOS:UIAbility组件生命周期--UIAbility组件启动模式

UI界面的应用组件&#xff0c;主要用于和用户交互。 UIAbility组件生命周期 UIAbility的生命周期包括Create、 onWindowStageCreate、Foreground、Background、onWindowStageDestroy Destroy四个状态 UIAbility组件启动模式 singleton&#xff08;单实例模式&#xff09;…

详解RTC:以华人文化打造链上生态

文化是人类在发展的历史长河中淘洗出来的智慧结晶&#xff0c;随着人类社会的进步和变迁&#xff0c;经历了从口口相传到互联网等不同历史时代的传承和创新。在数字技术飞速发展的当今&#xff0c;区块链技术为文化的创新与传承提供了全新的空间和方式&#xff0c;使其得以在新…

ACL与NAT

目录 一、ACL &#xff08;一&#xff09;ACL基本理论 &#xff08;二&#xff09;ACL的类型 1.基本ACL 2.高级ACL 3.二层ACL &#xff08;三&#xff09;基本原理 &#xff08;四&#xff09;项目实验 通配符掩码 二、NAT &#xff08;一&#xff09;基本理论 &am…

ansible的基本使用

本章主要介绍在RHEL8中如何安装ansible 及 ansible 的基本使用。 ansible是如何工作的在 RHEL8中安装ansible编写ansible.cfg和清单文件ansible 的基本用法 如果管理的服务器很多&#xff0c;如几十台甚至几百台&#xff0c;那么就需要一个自动化管理工具了&#xff0c; ansi…

【人生感悟】涅槃重生

哪里更容易挣钱&#xff0c;哪里更有发展的空间 心很定 如何做个内心强大的人 首先、要为自己而活。把你全部注意力和能量全部收回到你这个人本身身上&#xff0c;不要去在意别人对你的评价&#xff0c;不要去猜测别人的想法&#xff0c;不要急切的向外界证明你自己。 第二…

Elasticsearch Spring Data集成-05

Elasticsearch集成 Spring Data是一个用于简化数据库、非关系型数据库、索引库访问&#xff0c;并支持云服务的开源框架。其主要目标是使得对数据的访问变得方便快捷&#xff0c;并支持 map-reduce框架和云计算数据服务。Spring Data可以极大的简化JPA(Elasticsearch…)的写法…

Linux wc命令教程:如何有效地统计文件的行数、字数和字符数(附案例详解和注意事项)

Linux wc命令介绍 wc命令在Linux中是一个非常实用的工具&#xff0c;全称为word count&#xff0c;主要用于统计文本文件中行的数量、单词的数量以及字符的数量。 Linux wc命令适用的Linux版本 wc命令在大多数Linux发行版中都是默认安装的&#xff0c;包括但不限于Ubuntu, D…