黑马点评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.hqwc.cn/news/277675.html

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

相关文章

wpf devexpress如何使用AccordionControl

添加一个数据模型 AccordionControl可以被束缚到任何实现IEnumerable接口的对象或者它的派生类&#xff08;例如IList,ICollection&#xff09; 如下代码例子示范了一个简单的数据模型使用&#xff1a; using System.Collections.Generic;namespace DxAccordionGettingStart…

说说限流处理

对于限流&#xff0c;从一个完整的请求链路上来看的话&#xff0c;可以分几块&#xff0c;有nginx接入层网关的限流&#xff0c;微服务网关gateway的限流&#xff0c;在业务层我们也可以实现自己的限流逻辑&#xff0c;Redission和Google的Guava包本身也提供了一些限流工具。 而…

分类信息网商业运营版源码系统:适合各类行业分类站点建站 带安装部署教程

随着互联网的快速发展&#xff0c;信息分类网站在各个行业中得到了广泛应用。为了满足不同行业的需求&#xff0c;罗峰给大家分享一款适合各类行业分类站点建站的商业运营版源码系统。该系统旨在提供一套完整的解决方案&#xff0c;帮助用户快速搭建自己的分类信息网站&#xf…

[算法总结] 十大排序算法

[算法总结] 十大排序算法 简介&#xff1a; 本文首发于我的个人博客&#xff1a;尾尾部落排序算法是最经典的算法知识。因为其实现代码短&#xff0c;应该广&#xff0c;在面试中经常会问到排序算法及其相关的问题。一般在面试中最常考的是快速排序和归并排序等基本的排序算法…

LVS负载均衡集群——NAT地址转换模式与DR直接路由模式

1. LVS集群基本介绍 Cluster&#xff0c;集群、群集。 由多台主机构成&#xff0c;但对外只表现为一个整体&#xff0c;只提供一个访问入口&#xff08;域名或IP地址&#xff09;&#xff0c;相当于一台大型计算机。 2. 集群的类型 2.1 负载均衡群集&#xff08;Load Balanc…

静态HTTP应用在移动设备上的优化

随着移动设备的普及&#xff0c;越来越多的用户通过手机、平板等设备访问Web应用。对于静态HTTP应用来说&#xff0c;如何在移动设备上提供更好的用户体验和性能是一个值得关注的问题。本文将介绍一些静态HTTP应用在移动设备上的优化技巧。 一、响应式设计 响应式设计是一种让…

Leetcode 455 分发饼干

题意理解&#xff1a; 小孩的饭量&#xff1a; [1,2,7,10] 饼的大小&#xff1a; [1,3,5,7] 当饼的大小>小孩饭量时&#xff0c;小孩就能够吃饱。 求如何分配饼让更多的小孩子能够吃饱。 解题思路&#xff1a; 两种思路&#xff1a; 先把胃口小的孩子用较小的饼来喂饱—…

基于JavaWeb+SSM+Vue微信小程序的移动学习平台系统的设计和实现

基于JavaWebSSMVue微信小程序的移动学习平台系统的设计和实现 源码获取入口Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码获取入口 Lun文目录 第1章 绪论 1 1.1 课题背景 1 1.2 课题意义 1 1.3 研究内容 2 第2章 开发环…

深度学习环境配置

一、Anaconda安装 下载&#xff1a;从清华大学开源软件镜像下载 镜像网址 出现base即为安装成功&#xff1a; 检查显卡的驱动是否正确安装&#xff1a; &#xff08;GPU可以显示出名称&#xff09; GPU0是集显集成显卡是主板自带的显卡。 GPU1是独显即独立显卡&#xff0c…

计算机网络:物理层(三种数据交换方式)

今天又学到一个知识&#xff0c;加油&#xff01; 目录 前言 一、电路交换 二、报文交换 三、分组交换 1、数据报方式 2、虚电路方式 3、比较 总结 前言 为什么要进行数据交换&#xff1f; 一、电路交换 电路交换原理&#xff1a;在数据传输期间&#xff0c;源结点与…

PR模板,漂亮的文字帖子视频模板,方形标题PR项目工程文件下载

Premiere Pro模板&#xff0c;具有6个方形设计PR视频帖子标题文字PR项目工程文件。使用附带的颜色控制器调整和修改颜色&#xff0c;与您自己的品牌相匹配。使用这些效果来增强视频画面。包括视频教程。 适用软件&#xff1a;PR2019 | 分辨率&#xff1a;10801080&#xff08;方…

php入门、安装wampserver教程

php声称是全世界最好的语言&#xff0c;今天这篇文章就带大家入门学习php&#xff0c;php和python、javasript一样&#xff0c;是一种弱类型的脚本语言。 一、php开发环境搭建 作为初学者&#xff0c;学习php建议安装wampserver&#xff0c;wampserver是包含了apache、php和mys…