本篇文章给大家带来了关于redis的相关知识,其中主要介绍了关于分布式锁是什么?redis又是怎么实现分布式锁的?需要满足什么条件?下面一起来看一下吧,希望对需要的朋友有帮助。
分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。
分布式锁应该满足的条件:
常见的分布式锁有三种:
Mysql:mysql本身就带有锁机制,但是由于mysql性能本身一般,所以采用分布式锁的情况下,其实使用mysql作为分布式锁比较少见
Redis:redis作为分布式锁是非常常见的一种使用方式,现在企业级开发中基本都使用redis或者zookeeper作为分布式锁,利用setnx这个方法,如果插入key成功,则表示获得到了锁,如果有人插入成功,其他人插入失败则表示无法获得到锁,利用这套逻辑来实现分布式锁
Zookeeper:zookeeper也是企业级开发中较好的一个实现分布式锁的方案

实现分布式锁时需要实现的两个基本方法:
获取锁:
释放锁:
基于Redis实现分布式锁原理:
SET resource_name my_random_value NX PX 30000
利用NX的原子性,多个线程并发时,只有一个线程可以设置成功,设置成功表示获得锁,可以执行后续的业务处理;如果出现异常,过了锁的有效期,锁自动释放;
1、定义ILock接口
一览妙笔
自媒体、编剧、营销人员写作工具
50
查看详情
public interface ILock extends AutoCloseable {
/**
* 尝试获取锁
*
* @param timeoutSec 锁持有的超时时间,过期后自动释放
* @return true代表获取锁成功;false代表获取锁失败
*/
boolean tryLock(long timeoutSec);
/**
* 释放锁
* @return
*/
void unLock();
}2、基于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:";
@Override
public 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);
}
@Override
public void unLock() {
//通过del删除锁
stringRedisTemplate.delete(KEY_PREFIX + name);
}
@Override
public 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) + "-";
@Override
public 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);
}
@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);
}
}
@Override
public void close() {
unLock();
}
}问题分析:
上述释放锁的代码依然存在锁误删问题,当线程1获取锁中的线程标识,并根据标识判断是自己的锁,这时锁到期自动释放,恰好线程2尝试获取锁,并拿到了锁,此时线程1依然执行释放锁的操作,就导致误删了线程2持有的锁。
原因在于,由j*a代码实现的释放锁流程不是原子操作,存在线程安全问题。
解决方案:
Redis提供了Lua脚本功能,在一个脚本中编写多条Redis命令,可以确保多条命令执行时的原子性。
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) + "-";
@Override
public 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);
}
@Override
public 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<Boolean> redisScript = RedisScript.of(script, Boolean.class);
stringRedisTemplate.execute(redisScript,
Collections.singletonList(KEY_PREFIX + name),
ID_PREFIX + Thread.currentThread().getId());
}
@Override
public void close() {
unLock();
}
}推荐学习:《Redis视频教程》
以上就是聊聊分布式锁原理及Redis如何实现分布式锁的详细内容,更多请关注其它相关文章!
# 分布式锁
# 自己的
# 中阳网站推广售后服务
# 网站建设人员安排方案
# 河南推广行业网站建站
# 海鲜店营销推广策略
# 完美的网站推广方案
# 设计网站与推广
# 武汉问答营销推广哪里有
# seo交易网
# 道县水文站网站建设
# seo综合查询工具广告
# 加锁
# 如何实现
# 多条
# 见性
# 较高
# 都能
# 互斥
# 客户端
# 多个
# 后端
# Redis
相关栏目:
【
Google疑问12 】
【
Facebook疑问10 】
【
优化推广96088 】
【
技术知识133117 】
【
IDC资讯59369 】
【
网络运营7196 】
【
IT资讯61894 】
相关推荐:
芒果TV官网登录入口 芒果TV官方网站登录入口
Fedora怎么安装 Fedora Workstation安装步骤
虫虫漫画排行榜单入口_虫虫漫画编辑推荐入口
Lar*el 关联查询:同时筛选父表与子表数据的高效策略
如何查找哪个composer包引入了特定的依赖?
优化 React onClick 事件处理:函数引用与箭头函数的对比
Sublime Text怎么关闭自动完成_Sublime禁用Auto Complete设置
使用VS Code调试Python代码:从入门到精通
汽水音乐网页版登录 汽水音乐网页端官方入口
使用VS Code作为你的个人知识管理系统
CSS过渡与滚动滚动事件结合应用_scroll与transition动画
如何用Golang优化微服务间请求性能_Golang 微服务请求性能优化方法
Sublime怎么配置YAML文件格式化_Sublime YAML Formatter插件教程
怎样设置开机后自动运行某个程序_Windows启动文件夹与任务计划【自动化】
GBA模拟器手柄按键设置
QQ网站入口直接登录 QQ官方正版登录页面
邦丰播放器频道搜索设置
《新三国志曹操传》游历事件袁尚突围攻略
教资成绩怎么查询
J*aScript模拟悬停与点击:自动化网页动态元素交互指南
抖音网页版官方链接 抖音网页版官网链接入口
FotoBalloon图片左右镜像教程
如何在Python中安全地将环境变量转换为整数并满足Mypy类型检查
抖音评论无法发送如何修复 抖音评论功能操作指南
深入理解随机递归函数的确定性:内部节点、叶节点与时间复杂度分析
《饿了么》拼好饭点外卖教程2025
Go App Engine 项目结构与包管理深度指南
铁路12306官网登录入口 铁路12306在线购票官方平台
发布小红书怎么屏蔽粉丝?屏蔽粉丝能看到吗?
《kimi智能助手》制作ppt教程
MacBook Pro词典使用指南
J*a实现任务清单管理_集合框架综合入门练手
《金山词霸》语音翻译方法
《虎扑》取消评分记录方法
铁路12306入口 铁路12306官网版入口登录网址
在PySimpleGUI中实现键盘按键绑定按钮事件
Mac hosts文件在哪里_Mac修改hosts文件详细教程
VB表达式书写规则解析
感染了幽门螺杆菌一定会导致胃癌吗?蚂蚁庄园今日答案最新11.30
我居然低估了 DeepSeek,这次更新它做到了这些!
汽水音乐在线入口 汽水音乐网页端官方页面快速打开
msn官方入口2025登录 msn官网2025直达首页入口
手机雨课堂网页版入口免登录 雨课堂网页版可点击直接进入
QQ邮箱注册地址 免费获取QQ邮箱账号
Firefox OS应用开发:解决XMLHttpRequest跨域请求阻塞问题
Win10共享文件夹设置方法 Win10局域网文件共享全攻略【教程】
什么是Satis,如何用它搭建一个私有的composer仓库?
猫眼电影app如何筛选支持退改签的影院_猫眼电影退改签影院筛选方法
sublime如何处理超大文件不卡顿 _sublime打开大日志文件技巧
动漫岛在线动漫网 动漫岛动漫在线观看官方入口
2023-01-27
运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。