分布式锁原理及Redis如何实现分布式锁(分布式锁的实现方式redis)

admin200656年前3条评论

一淘模板给人人带来了对于于redis的相干知识,其中主要介绍了对于于散布式锁是甚么?Redis又是怎么实现散布式锁的?需要满足甚么条件?下面一起来看一下吧,希望对于需要的朋侪有帮助。

 分布式锁原理及Redis如何实现分布式锁(分布式锁的实现方式redis) 技术教程

一、散布式锁基础情理

散布式锁:满足散布式系统或者集群形式下多进程可见而且互斥的锁。

散布式锁应当满足的条件:

可见性:多个线程都能看到相同的效果,细致:这其中央说的可见性并非并发编程中指的内存可见性,只是说多个进程之间都能感知到变化的意思

互斥:互斥是散布式锁的最基础的条件,使患上程序串行实行

高可用:程序不易崩溃,常常刻刻都保障较高的可用性

高性能:因为加锁自身就让性能升高,所有对于散布式锁自身需要他就较高的加锁性能以及开释锁性能

平安性:平安也是程序中必不可少的一环

罕见的散布式锁有三种:

Mysql:mysql自身就带有锁机制,然而因为mysql性能自身失常,以是接收散布式锁的状况下,实在应用mysql作为散布式锁对于比少见

Redis:redis作为散布式锁是非常罕见的一种应用形式,现在企业级开辟中基础都应用redis或者zookeeper作为散布式锁,应用setnx这个方法,如果插入key胜利,则示意获取到了锁,如果有人插入胜利,其余人插入失利则示意无奈获取到锁,应用这套逻辑来实现散布式锁

Zookeeper:zookeeper也是企业级开辟中较好的一个实现散布式锁的计划

 分布式锁原理及Redis如何实现分布式锁(分布式锁的实现方式redis) 技术教程

二、基于Redis实现散布式锁

实现散布式锁时需要实现的两个基础方法:

获取锁:

互斥:确保只能有一个线程获取锁

非阻塞:试验一次,胜利返回true,失利返回false

开释锁:

手动开释

超时开释:获取锁时增添一个超时间阴

基于Redis实现散布式锁情理:

SET resource_name my_random_value NX PX 30000

resource_name:资本名称,可依据分比方的营业区分分比方的锁

my_random_value:随机值,每一个线程的随机值都分比方,用于开释锁时的校验

NX:key不存在时配置胜利,key存在则配置不胜利

PX:主动失效时日,浮现异样状况,锁能够过期失效

应用NX的原子性,多个线程并发时,只有一个线程能够配置胜利,配置胜利示意获取锁,能够实行后续的营业解决;如果浮现异样,过了锁的实用期,锁主动开释;

版本一

一、界说ILock接口

public interface ILock extends AutoCloseable {/** * 试验获取锁 * * @param timeoutSec 锁持有的超时间阴,过期后主动开释 * @return true代表获取锁胜利;false代表获取锁失利 */boolean tryLock(long timeoutSec); /** * 开释锁 * @return */void unLock();}

二、基于Redis实现散布式锁—RedisLock

public class SimpleRedisLock {private final StringRedisTemplate stringRedisTemplate;private final String name; public SimpleRedisLock(StringRedisTemplate stringRedisTemplate, String name) {this.stringRedisTemplate = stringRedisTemplate;this.name = name;} private static final String KEY_PREFIX = "lock:"; @Overridepublic boolean tryLock(long timeoutSec) {//获取线程标识String threadId = Thread.currentThread().getId();//获取锁Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success);} @Overridepublic void unLock() {//通过del删除了锁stringRedisTemplate.delete(KEY_PREFIX + name);} @Overridepublic void close() {unLock();}}

锁误删问题

问题说明:

持有锁的线程1在锁的外部浮现了阻塞,这时锁超时主动开释,这时线程2试验获取锁,而后线程2在持有锁实前进程中,线程1反应过去,连续实行,走到了删除了锁逻辑,此时就会把本应当属于线程2的锁停止删除了,这便是锁误删的状况。

解决心划:

在存入锁时,放入自身线程的标识,在删除了锁时,坚定以后这把锁的标识是否自身存入的,如果是,则停止删除了,如果否,则一直止删除了。

版本二:解决锁误删问题

public class SimpleRedisLock {private final StringRedisTemplate stringRedisTemplate;private final String name; public SimpleRedisLock(StringRedisTemplate stringRedisTemplate, String name) {this.stringRedisTemplate = stringRedisTemplate;this.name = name;} private static final String KEY_PREFIX = "lock:";private static final String ID_PREFIX = UUID.randomUUID().toString(true) + "-"; @Overridepublic boolean tryLock(long timeoutSec) {//获取线程标识String threadId = ID_PREFIX + Thread.currentThread().getId();//获取锁Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success);} @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);}} @Overridepublic void close() {unLock();}}

锁开释的原子性问题

问题剖析:

上述开释锁的代码依然存在锁误删问题,当线程1获取锁中的线程标识,并依据标识坚定是自身的锁,这时锁到期主动开释,恰好线程2试验获取锁,并拿到了锁,此时线程1依然实行开释锁的操纵,就以致误删了线程2持有的锁。

原因在于,由java代码实现的开释锁流程不是原子操纵,存在线程平安问题。

解决心划:

Redis供应了Lua剧本色能,在一个剧本中编写多条Redis命令,能够确保多条命令实行时的原子性。

版本三:调用Lua剧本革新散布式锁

public class SimpleRedisLock implements ILock {private final StringRedisTemplate stringRedisTemplate;private final String name; public SimpleRedisLock(StringRedisTemplate stringRedisTemplate, String name) {this.stringRedisTemplate = stringRedisTemplate;this.name = name;} private static final String KEY_PREFIX = "lock:";private static final String ID_PREFIX = UUID.randomUUID().toString(true) + "-"; @Overridepublic boolean tryLock(long timeoutSec) {//获取线程标识String threadId = ID_PREFIX + Thread.currentThread().getId();//获取锁Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success);} @Overridepublic void unLock() {String script = "if redis.call("get",KEYS[1]) == ARGV[1] then\n" +" return redis.call("del",KEYS[1])\n" +"else\n" +" return 0\n" +"end";//通过实行lua剧本实现锁删除了,能够校验随机值RedisScript redisScript = RedisScript.of(script, Boolean.class);stringRedisTemplate.execute(redisScript,Collections.singletonList(KEY_PREFIX + name),ID_PREFIX + Thread.currentThread().getId());} @Overridepublic void close() {unLock();}}

 

你可能想看:

本文链接:https://addon.ciliseo.com/fen-bu-shi-suo-yuan-li-ji-redis-ru-he-shi-xian-fen-bu-shi-suo.html

Redis分布式锁分布式如何实现原理线程标识多个原子脚本问题也是到了性能如何
问题的英文问题少年学校管教机构哪家正规问题大全问题清单问题英语怎么读问题整改清单及整改措施情况问题查摆清单及整改措施问题儿童都来自异界问题的拼音问题学生是我的相亲对象问题清单及整改台账问题清单及整改措施问题清单及整改措施2024问题解决型对策表前四项的先后顺序依次是问题查摆清单及整改措施2024问题图片问题导向问题台账及整改措施表问题英文问题王子问题住宅问题意识问题在经济根子在政治问题的关键是找到关键的问题也是冬天也是春天也是什么意思也是冬天也是春天电子书免费阅读也是的拼音也是一种幸福半命题作文也是什么结构也是一种美作文也是英文也是造句也是冬天也是春天读后感也是冬天也是春天迟子建免费全文阅读也是冬天也是春天迟子建免费阅读全文也是冬天也是春天免费全文阅读也是冬天也是春天迟子建在线阅读也是冬天也是春天好句摘抄也是冬天也是春天迟子建免费全文也是一种小欢喜作文600字也是冬天也是春天简介也是meaninginenglish也是inenglish也是冬天也是春天也是toenglish也是冬天也是春天在线阅读也是冬天也是春天pdf也是集也是translationtoenglish也是inchinese多个pdf怎么合并成一个pdf多个excel表格汇总到一张表多个表格如何合并到一张表里多张图片怎么合成一张图片多个独立excel汇总到一张表多个子宫肌瘤怎么办才最好多个视频怎么合成一个视频多个淋巴结肿大是怎么回事多个条件if函数的使用方法多个肺结节是怎么回事严重吗多个excel表格数据汇总到一个表格多个pdf合并成一个pdf多个pdf合并成一个pdf在线免费多个excel文件合并成一个excel文件多个快递点二次收费多个表格数据汇总到一个表格多个表合并成一个表多个机器人是如何实现同步舞蹈的?多个word文档合并成一个word文档多个扫描件怎么合成一个pdf多个pdf合并多个excel合并成一个sheet多个随机数生成器多个word文档合并多个excel合并多个微信号多个图片合成一个图片多个sheet合并到一个sheet多个图片合并pdf多个压缩包一起解压原理是什么意思原理的英文原理图原理和定律的区别原理有哪些原理图怎么生成PCB原理图怎么看原理血戒原理框图原理图用什么软件画原理视界原理图英文原理英语原理创新原理效应原理框图怎么画原理英文原理图英文原理英语

网友评论

  • 2025-02-2118:10:06

    如何实现为我们提供了一系列实际可操作的指南,让人们学会用智慧与行动把理想变成现实。

  • 2025-02-2317:27:17

    问题不仅是思维的灯塔,更是探索未知世界的航标。

  • 2025-02-2508:17:25

    到了是一部精彩的作品,无论是情感深度还是情节布局都展现了作者出色的文学功底。

扫一扫二维码添加客服微信

关于我们建站招商建站服务