大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
为什么需要分布式锁
分布式锁是实现用户进程同步的一种方式,需要注意的是,Redis是分布式锁实现的一种技术,而不是作用对象
多用户进程请求服务的场景很多,为什么分布式锁并不普遍应用?首先需要定义一下分布式锁的原理和使用场景
使用场景
原子锁—线程同步,一个程序下的多线程之间对于共享变量进行同步,如计数器
分布式锁—进程同步,集群下的多服务进程之间对于共享资源进行同步,如数据库
可以明确的是数据库已经实现这种“锁”的机制了,因为它的事务锁机制,虽然多个用户I/O之间会出现数据短暂的不一致,长期还是可以保证数据一致性的
不需要进程同步的场景:因为多个用户进程的请求是相对独立的,不受彼此影响或影响不大的(两个都不是持久化请求,即写+写),例如,A开放权限B访问页面属于写+读,同时搜索信息属于读+读
需要进程同步的场景:多个用户进程的请求是互相影响的(两个都是持久化请求,写+写),例如,秒杀系统防止超卖,占位抢票
Redis加锁
需要满足以下特性,因此用到两个命令
独占性:如果锁已经被占用,线程需要阻塞等待—setnx
时效性:锁超过一定时间自动释放—setex
对于共享的Jedis连接,操作需要原子性:
jedis.set(KEY,VALUE,”NX”,”PX”,EXPIRE_TIME);
KEY—锁的密钥
VALUE—用户请求ID/线程ID
“NX”—setnx
“PX”—setex
EXPIRE_TIME—失效时间
代码示例
private static final String LOCK_SUCCESS = "OK";
public static boolean lock(Jedis jedis,String KEY,String VALUE,int EXPIRE_TIME) {
String success = jedis.set(KEY, VALUE, "NX", "PX", EXPIRE_TIME);
return LOCK_SUCCESS.equals(success);
}
Redis解锁
需要解决一个问题,因此用到两个命令
避免误删:进程A超时,锁被释放,进程B获得锁,此时进程A删除了KEY,解决方法“解铃还须系铃人”,需要校验传入的VALUE,即用户请求ID,伪代码if get(KEY)=VALUE then del(KEY)
同样地,需要通过一个Jedis的命令实现原子性
jedis.eval(SCRIPT, KEY, VALUE);
SCRIPT—LUA脚本来完成KEY-VALUE校验和删除KEY两个步骤,保证原子性
KEY—锁的密钥
VALUE—用户请求ID/线程ID
代码示例
private static final Long RELEASE_SUCCESS = 1L;
public static boolean release(Jedis jedis,String KEY,String VALUE) {
String script="if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object success = jedis.eval(script, Collections.singletonList(KEY),Collections.singletonList(VALUE));
return RELEASE_SUCCESS.equals(success);
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/197874.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...