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

news2024/12/24 22:09:20

实战篇-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;
    }

    @Override
    public 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;
    }

    @Override
    public 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);  //防拆箱空指针
    }

    @Override
    public void unlock() {
        //调用lua脚本
        stringRedisTemplate.execute(UNLOCK_SCRIPT,
                Collections.singletonList(KEY_PREFIX + name),
                ID_PREFIX + Thread.currentThread().getId()
        );
    }

    /*
    *
    @Override
    public 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.coloradmin.cn/o/1320201.html

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

相关文章

C语言是否已经跟不上社会需求?

今日话题。C语言是否已经跟不上社会需求&#xff1f;一个问题的提出者说&#xff0c;几天前他受到老板的批评&#xff0c;因为他只精通C语言编程&#xff0c;无法满足老板的需求。实际上&#xff0c;C语言在嵌入式行业中仍然具有极高的价值。它高效、可移植&#xff0c;并广泛用…

选择正确的自动化测试工具:打造高效测试流程的必备利器!

摘要 自动化测试正在逐步取代部分手动测试&#xff0c;因为它可以节省时间并提高测试质量。特别是在进行回归测试的情况下&#xff0c;自动化可以通过多种方式提高效率。手动进行重复测试是浪费时间和资源。此外&#xff0c;由于重复测试可能会遗漏&#xff0c;因此存在一定的…

Android Stuido报错处理

仅用作报错记录。防止以后出项问题不知如何解决。 报错1 Dependency‘androidx.annotation:xx requires libraries and applications … 需要修改CompileSDKVersion更改为报错中提示的版本 打开项目build.gradle文件&#xff0c;将compileSdk和targetSdk修改为报错中提示的版…

从数藏到链游,最近爆火的链游理想城,一天直接干爆服务器!

大家好&#xff0c;我是吴军&#xff0c;一家软件开发公司的营销经理 今天我们来聊聊链游以及数字藏品&#xff0c;2022年4月开始&#xff0c;一众数藏平台犹如雨后春笋冒出来&#xff0c;由ibox牵头&#xff0c;开始了一场掘金盛宴&#xff0c;许多大学生都相继入场&#xff…

【1.7计算机组成与体系结构】主存编址计算

目录 1.主存编址2.主存编址计算公式3.例题&#xff1a; 1.主存编址 1bit(比特位) 1B(字节)8bit(比特位) 1KB1024B 1MB1024KB 1GB1024MB 2.主存编址计算公式 &#x1f534;存储单元 存储单元个数最大地址-最小地址1 &#x1f534;编址内容 按字编址:存储体的存储单元是字存储…

专科毕业,应届生零基础如何七天搞定自动化测试?

现在很多测试人员有些急于求成&#xff0c;没有任何基础想当然的&#xff0c;要在一周内上手自动化测试。 在自动化的过程中时候总有人会犯很低级的问题&#xff0c;有语法问题&#xff0c;有定位问题&#xff0c;而且有人居然连__init__.py 文件名都弄错误&#xff0c;还有将…

90%的人学Python爬虫都干过这种事,别不承认!

可以说&#xff0c;我是因为想批量下载一个网站的图片&#xff0c;才开始学的python爬虫。当一张一张图片自动下载下来时&#xff0c;满满的成就感&#xff0c;也满满的罪恶感……哈哈哈&#xff01;&#xff01;&#xff01;窈窕淑女&#xff0c;君子好逑&#xff0c;这篇文章…

防止反编译,保护你的SpringBoot项目

ClassFinal-maven-plugin插件是一个用于加密Java字节码的工具&#xff0c;它能够保护你的Spring Boot项目中的源代码和配置文件不被非法获取或篡改。下面是如何使用这个插件来加密test.jar包的详细步骤&#xff1a; 安装并设置Maven&#xff1a; 首先确保你已经在你的开发环境中…

C/C++函数递归的趣味题

1、汉诺塔问题 题目&#xff1a; 先来分析一下当圆盘数较小时的操作步骤。 代码 //递归求解汉诺塔问题 void move(char, char); void HanoiTower(int, char, char, char); int main() {cout << "请输入A柱上的圆盘数量&#xff1a;";int n;cin >> n;Han…

Java研学-JavaScript 进阶

一 JS 的 DOM 1 概述 DOM 是 Document Object Model 文档对象模型的缩写。根据 W3C 的 DOM 规范&#xff0c;它是一种与浏览器&#xff0c;平台&#xff0c;语言无关的接口&#xff0c;能够动态地修改 XML 和 HTML。   D&#xff1a;文档 – HTML文档 或 XML 文档   O&…

物联网在能源管理中的应用——青创智通工业物联网解决方案

随着全球能源资源的日益紧张和环境问题的日益突出&#xff0c;能源管理已成为当今社会的重要议题。物联网技术的快速发展为能源管理提供了新的解决方案。本文将介绍物联网在能源管理中的应用及其优势。 一、物联网在能源管理中的应用 1. 智能电网 智能电网是物联网在能源管理中…

【基于BP神经网络的房价预测系统设计与实现】

基于BP神经网络的房价预测系统设计与实现 摘要1. 引言2. 数据获取与预处理3. 数据分析与可视化4. 系统功能设计4.1 用户登录注册4.2 房价数据展示4.3 房价变化趋势4.4 各区房价对比4.5 房间数和朝向分析4.6 房价预测 5. 创新点与意义6. 结论与展望结尾 摘要 本文介绍了一项基于…

Video anomaly detection with spatio-temporal dissociation 论文阅读

Video anomaly detection with spatio-temporal dissociation 摘要1.介绍2.相关工作3. Methods3.1. Overview3.2. Spatial autoencoder3.3. Motion autoencoder3.4. Variance attention module3.5. Clustering3.6. The training objective function 4. Experiments5. Conclusio…

骨传导耳机跟开放式耳机有什么关系?骨传导耳机和气传导耳机谁更值得入手?

开放式耳机是指开放双耳佩戴的耳机&#xff0c;骨传导耳机也算开放式耳机的一种&#xff0c;除了骨传导耳机外&#xff0c;还有气传导耳机&#xff0c;这两种耳机都算开放式耳机&#xff0c;不过传声方式有所不同。 骨传导耳机&#xff1a;通过颅骨震动来进行传导声音&#xff…

更长的 GPT-4 对话 token 上限,如何影响我的翻译工作流?

&#xff08;注&#xff1a;本文为小报童精选文章&#xff0c;已订阅小报童或加入知识星球「玉树芝兰」用户请勿重复付费&#xff09; 顺便聊聊生成式 AI 对你将来的工作流究竟有什么影响。 惊喜 Setapp 里面的 Typingmind 终于可以支持 128K token 窗口的 GPT-4 Turbo 了。只要…

5G工业物联网网关,比4G工业网关强在哪里?

​随着5G技术的广泛应用&#xff0c;越来越多的行业开始探索如何利用5G网络提升效率和创新能力。其中&#xff0c;工业物联网领域是受益最大的领域之一。作为连接物联网设备和网络的关键组件&#xff0c;5G工业物联网网关在这个变革中发挥着至关重要的作用。本文将深入探讨5G工…

Linux+Docker+Gitee+Jenkins自动化部署.NET Core服务

目录 一、安装Jenkins 1、跟新yum包 2、查询镜像 3、拉取镜像 4、创建Jenkins工作目录&#xff0c;并将容器内目录挂载到此目录上 5、启动Jenkins容器 二、Jenkins配置 1、Jenkins安装gitee码云插件 2、创建私人令牌 3、Jenkins添加全局凭据 4、系统配置 三、构建任…

运筹学经典问题(七):旅行商问题(TSP)

问题描述 给定一系列城市和每对城市之间的距离&#xff0c;求解访问每座城市一次并回到起始城市的最短回路。 数学建模 集合&#xff1a; V V V&#xff1a;城市集合 常量&#xff1a; c i j c_{ij} cij​&#xff1a;城市 i i i到城市 j j j之间距离, i ≠ j i \neq j i…

Unity SRP 管线【第四讲:URP 阴影】

URP 全文源码解析参照 引入 在UniversalRenderer.cs/ line 505行处 此处已经准备好了所有渲染数据&#xff08;所有数据全部存储在了renderingData中&#xff09; 我们只用renderingData中的数据初设置mainLightShadows bool mainLightShadows m_MainLightShadowCasterPass…

tamper编写

借鉴 sqlmap之tamper脚本编写_sqlmap tamper编写-CSDN博客 先看一个tamper的例子 栗子 escapequotes.py #!/usr/bin/env python""" Copyright (c) 2006-2023 sqlmap developers (https://sqlmap.org/) See the file LICENSE for copying permission "&…