分布式锁(仅供自己参考)

分布式锁:满足分布式系统或集群式下多进程可见并且互斥的锁(使用外部的锁,因为如果是集群部署,每台服务器都有一个对应的tomcat,则每个tomcat的jvm就不同,锁对象就不同(加锁的机制,每个jvm有一个锁监听器,里面存放着是否含有所有加锁的对象。有一次线程来,首先判断该线程所具有的所要加锁的对象在锁监视器中是否有,有则让它等待,没有的话则将加锁的对象加进来,再有线程来判断,则和上面的流程一样))(自己理解的流程,可能不对,请指错)

redis实现分布式锁:

一些主要代码:

因为在加锁的时候new的不同的对象,使得每一个name都是不同的。

如果是在高并发的情况下,会有一点的影响(具体的影响是问的chatgpt的)     

        在高并发情况下,如果每个线程都频繁创建和销毁大量对象,这会对Java堆内存产生一定的影响,主要体现在以下几个方面:

  1. 内存使用压力增大:

    • 大量的对象实例占用堆内存空间,可能会导致堆内存使用率急剧上升。
    • 如果不及时回收无用对象,会造成内存溢出(OutOfMemoryError)的风险。
  2. 垃圾回收压力增大:

    • 大量短暂对象的频繁创建和销毁,会增加Java虚拟机的垃圾回收压力。
    • 垃圾回收频率提高,可能会导致应用的性能下降。
  3. 线程间资源竞争:

    • 多个线程同时在堆内存中分配和释放对象,可能会产生线程安全问题。
    • 如果对象的创建和销毁不够规范,可能会导致内存泄漏等问题。
  4. 缓存命中率下降:

    • 大量短暂对象的创建可能会污染CPU缓存,降低缓存命中率。
    • 这会增加内存访问的开销,拖慢整体应用的性能。

可以采用单例模式,也就是在将锁对象作为成员变量,而不是局部变量。(代码参考(参考这里1))

package com.hmdp.utils;import org.springframework.data.redis.core.RedisTemplate;import java.time.Duration;//redis实现的锁机制
public class OrderOneLock implements Lock {private RedisTemplate redisTemplate;private String name;private final String PREFIX_KEY = "lock:";public OrderOneLock(RedisTemplate redisTemplate, String name) {this.redisTemplate = redisTemplate;this.name = name;}@Overridepublic boolean tryLock(long timeOut) {long id = Thread.currentThread().getId();Boolean b = redisTemplate.opsForValue().setIfAbsent(PREFIX_KEY + name, id, Duration.ofSeconds(timeOut));return Boolean.TRUE.equals(b);}@Overridepublic void unLock() {redisTemplate.delete(PREFIX_KEY+name);}
}//加锁Long userId = UserHolder.getUser().getId();//获取锁,看是否获取成功OrderOneLock oneLock = new OrderOneLock(redisTemplate,"order:"+userId); //选择userId是因为每个用户只能选择一单,如果没有userid则全部都使用一单boolean b = oneLock.tryLock(120);if (!b){return Result.fail("只能购买一单");}//能执行到这里,说明加锁成功,则之后必须不管怎么都要释放锁,所以选择finallytry {IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();return proxy.getResult(voucherId, userId);} finally {oneLock.unLock();}

参考这里(1)

因为此代码较上边的代码,是为了避免在高并发的情况的大量的创建和销毁对象,而造成性能上的影响。但也是这段代码毕竟麻烦,在于是在销毁锁的时候需要传参数,毕竟有舍有得(具体业务具体分析)。

代码:

package com.hmdp.utils;import org.springframework.data.redis.core.RedisTemplate;import java.time.Duration;public class OrderOneLock implements Lock {private RedisTemplate redisTemplate;//private String name;private final String PREFIX_KEY = "lock:";private String workName; //具体的业务名字public OrderOneLock(RedisTemplate redisTemplate, String name) {this.redisTemplate = redisTemplate;this.workName = name;}@Overridepublic boolean tryLock(long timeOut,String name) {long id = Thread.currentThread().getId();Boolean b = redisTemplate.opsForValue().setIfAbsent(PREFIX_KEY + workName+name, id, Duration.ofSeconds(timeOut));return Boolean.TRUE.equals(b);}@Overridepublic void unLock(String name) {redisTemplate.delete(PREFIX_KEY+workName+name);}
}

上述代码还会造成一种情况,请看下图:

        由于线程1的阻塞,导致redis的key的过期。这时候key过期,线程2就可以拿到锁了,如果这时候线程1,业务完成结束,肯定是需要释放锁的,但这个时候释放的是线程2的锁,而不是线程1它本身的锁。线程2的锁释放之后,但是线程2的业务还未完成,线程3也就来了,导致了有两个线程同时运行,于我们加锁(只能由一个线程执行相违背),而且前一个线程会释放后一个线程的锁。

解决方案:

        给每一个线程的锁都弄一个标识,使得每一个线程都只能由它本身释放,或者过期(这里还没有解决会有多个线程同时执行)

        使用uuid和当前线程号给每一个线程一个标识。uuid在同一个jvm可能相同,但是在不同的jvm之间不同(每一个jvm运行在不同的机器或者虚拟机上)。原因:

  1. UUID生成算法: 在Java中,UUID通常使用RFC 4122中定义的算法生成。这个算法利用了时间戳、MAC地址、随机数等多种因素来生成唯一的UUID。

  2. 时间因素: 算法中使用了时间戳作为生成因素之一。不同的JVM,即使在同一时间生成,由于机器时钟的微小差异,也会导致生成的UUID不同。

  3. 空间因素: UUID的算法还会利用MAC地址作为生成因素。不同的JVM运行在不同的服务器/虚拟机上,MAC地址必不同,这也会导致生成的UUID不同。

           在加上同一个jvm上的线程号是不同的,也就构成了唯一一个标识(jvm使得线程号是递增的)

代码:(自己比较与上面代码的差别)

package com.hmdp.utils;import cn.hutool.core.lang.UUID;
import org.springframework.data.redis.core.RedisTemplate;import java.awt.*;
import java.time.Duration;public class OrderOneLock implements Lock {private RedisTemplate redisTemplate;private String name;private final String PREFIX_KEY = "lock:";private final String mark = UUID.randomUUID().toString(true)+"-";public OrderOneLock(RedisTemplate redisTemplate, String name) {this.redisTemplate = redisTemplate;this.name = name;}@Overridepublic boolean tryLock(long timeOut) {long id = Thread.currentThread().getId();Boolean b = redisTemplate.opsForValue().setIfAbsent(PREFIX_KEY +name, mark+id, Duration.ofSeconds(timeOut));return Boolean.TRUE.equals(b);}@Overridepublic void unLock() {long id = Thread.currentThread().getId();String o = (String) redisTemplate.opsForValue().get(PREFIX_KEY + name);String s = mark + id;if(s.equals(o)){redisTemplate.delete(PREFIX_KEY+name);}}
}

新的情况出现:

如上图:在线程1执行业务完成之后,需要释放锁,在已判断了他是属于他的锁,就要执行 redisTemplate.delete(PREFIX_KEY+name);这句时发生了阻塞(jvm的垃圾回收机制,导致所有代码都不能运行)。一直阻塞。阻塞时间超过了key的过期时间。锁释放。等到阻塞结束,这时又会有线程2进来,线程1也是执行 redisTemplate.delete(PREFIX_KEY+name);这句。这时候线程1就会释放线程2的锁。释放之后就会有线程3进来,这时就会有两个线程执行这个业务(发生了并发),不符合我们的要求。

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

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

相关文章

独立开发者系列(23)——Linux掌握小结

只要开发系统,就绕不开使用Linux服务器 ,而Linux除了使用BT面板进行初级管理,很多稍微高级点的管理,还是需要命令行进行的。这里总结在不需要精通的情况下,掌握常见命令和环境的相关配置。 (1&#xff09…

HI3559AV100四路IMX334非融合拼接8K视频记录

下班无事,写篇博客记录海思hi3559av100四路4K视频采集拼接输出8K视频Demo 一、准备工作: 软件:Win11系统、VMware虚拟机Ubuntu14、Hitool、Xshell等 硬件:HI3559AV100开发板4路imx334摄像头、串口线、电源等 附硬件图&#xff1…

来一场栈的大模拟(主要是单调栈)

一.栈模拟 二.单调栈求最大矩形面积 通常,直方图用于表示离散分布,例如,文本中字符的频率。 现在,请你计算在公共基线处对齐的直方图中最大矩形的面积。 图例右图显示了所描绘直方图的最大对齐矩形。 输入格式 输入包含几个测…

哪里有主机游戏店收费系统,佳易王电玩ps5ps4计时计费系统操作教程

哪里有主机游戏店收费系统,佳易王电玩ps5ps4计时计费系统操作教程 以下软件操作教程以,佳易王计时计费管理系统为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 一、软件程序图文讲解 1、主机游戏计时软件、电玩店计费软…

HumanoidBench——模拟仿人机器人算法有未来

概述 论文地址:https://arxiv.org/pdf/2403.10506 仿人机器人具有类似人类的外形,有望在各种环境和任务中为人类提供支持。然而,昂贵且易碎的硬件是这项研究面临的挑战。因此,本研究开发了使用先进模拟技术的 HumanoidBench。该基…

GTK是如何加密WLAN组播和广播数据的?

1. References WLAN 4-Way Handshake如何生成GTK?_tk bigtk gtk igtk-CSDN博客 2. 概述 在Wi-Fi网络中,单播、组播和广播帧的加密算法是由AP决定的。其中组播帧和广播帧的加密使用GTK密钥,其PTK的密钥结构如下图所示: GTK的组成…

2024 Q3 NAND闪存价格|企业级依然猛涨,消费级放缓

在企业领域持续投资于服务器基础设施,特别是在人工智能应用的推动下,企业级SSD需求增加的同时,消费电子市场却依旧疲软。加之NAND供应商在2024年下半年积极扩大生产,预计到2024年第三季度,NAND闪存供应充足率将上升至2…

“郑商企航”暑期社会实践赴美丽美艳直播基地开展调研

马常旭文化传媒网讯(记者张明辉报道)导读:2024 年 7 月 3 日,商学院暑期社会实践团“郑商企航”在河南省郑州市新密市岳村镇美丽美艳直播基地,展开了一场意义非凡的考察活动,团队成员深度调研了直播基地的产…

【系统架构设计】计算机组成与体系结构(二)

计算机组成与体系结构 计算机系统组成存储器系统前言主存储器存储器存储数量(计算) 辅助存储器(以磁盘为例)Cache存储器 流水线 计算机系统组成 存储器系统 前言 存储器用来存放程序和数据的部件,是一个记忆装置&am…

【自动驾驶/机器人面试C++八股精选】专栏介绍

目录 一、自动驾驶和机器人技术发展前景二、C在自动驾驶和机器人领域的地位三、专栏介绍四、订阅需知 一、自动驾驶和机器人技术发展前景 随着人工智能、机器学习、传感器技术和计算能力的进步,自动驾驶和机器人的技术水平不断提升,使得它们更加智能、可…

fatal error: napi.h: No such file or directory

使用Cmake-js构建基于node-addon-api的C扩展 基于node-addon官方的eample改造测试:https://github.com/nodejs/node-addon-examples Cmake-js的github给了一个例子,但是是基于NAN的,而不是node-addon-api:https://github.com/cma…

如何压缩视频大小不改变画质,视频太大怎么压缩变小

在现代生活中,视频已经成为我们记录生活、分享快乐的重要工具。但随之而来的问题就是视频文件体积过大,不仅占用大量存储空间,还难以在社交平台上快速分享。别担心,下面我就来教大家几种简单有效的方法,让视频文件轻松…

回溯算法-以医院信息管理系统为例

1.回溯算法介绍 1.来源 回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。 用回溯算法解决问题的一般步骤: 1、 针对所给问题,定义问题的解空间,它至少包含问题的一个(最优)解。 2 、确定易于搜…

移除元素的讲解,看这篇就够了!

一:题目 博主本文将用指向来形象的表示下标位的移动。 二:思路 1:两个整形,一个start,一个end,在一开始都 0,即这里都指向第一个元素。 2:在查到val之前,查一个&…

Jackson与FastJson时间Date转换问题

今天在开发Excel导出时发现一个Date类型的属性导出的不对,因为导出时将Vo装换成了Json, Vo类Date字段也添加了DateTimeFormat(pattern "yyyy-MM-dd"),JsonFormat(timezone "GMT8", pattern "yyyy-MM-dd"),那么这是为什么呢&#…

渲染农场怎么用更省钱?渲染100邀请码1a12

现在越来越多的设计师开始使用渲染农场,其中收费是个大问题,怎么用渲染农场才能更省钱呢?今天我们就来看下吧。 1、明确渲染方式 要根据不同情况选择合理的渲染方式,比如渲染农场就适合大场景渲染和紧急出图情况,其他…

前端JS特效第26波:jQuery日期时间选择器插件

jQuery日期时间选择器插件&#xff0c;先来看看效果&#xff1a; 部分核心的代码如下&#xff1a; <!DOCTYPE html> <html> <head lang"zh-CN"> <meta charset"UTF-8"> <title>jQuery日期时间选择器插件 - PHP中文网</t…

MySQL手注之布尔型盲注详解

布尔型盲注简介 基于布尔型SQL盲注即在SQL注入过程中&#xff0c;应用程序仅仅返回True&#xff08;页面&#xff09;和False&#xff08;页面&#xff09;。 这时&#xff0c;我们无法根据应用程序的返回页面得到我们需要的数据库信息。但是可以通过构造逻辑判断&#xff08;…

WSL2编译使用6.6版本内核

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、有什么变化二、下载6.6内核三、开始编译1.安装环境2.开始编译 四、使用1.杀死虚拟机2.防止内核文件3.修改配置文件 总结 前言 最近出了一件不大不小的事&a…

品牌文化五大维度,构建品牌竞争力的秘诀!

品牌文化对于企业的发展和成功至关重要。 品牌文化不仅是企业和消费者之间的纽带&#xff0c;也是企业内部员工的凝聚力。 在当今竞争激烈的市场环境中&#xff0c;建立一个有活力和影响力的品牌文化是每个企业都需要认真思考和实践的事情。 品牌文化的五大维度包括价值观、…