基于Redis实现分布式锁的几种坑你是否踩过《下》
简介:手把手教你彻底掌握分布式锁+原生代码编写
存在什么问题?
多个命令之间不是原子性操作,如setnx和expire之间,如果setnx成功,但是expire失败,且宕机了,则这个资源就是死锁
使用原子命令:设置和配置过期时间 setnx / setex
如: set key 1 ex 30 nx
java里面 redisTemplate.opsForValue().setIfAbsent("seckill_1","success",30,TimeUnit.MILLISECONDS)
业务超时,存在其他线程勿删,key 30秒过期,假如线程A执行很慢超过30秒,则key就被释放了,其他线程B就得到了锁,这个时候线程A执行完成,而B还没执行完成,结果就是线程A删除了线程B加的锁
可以在 del 释放锁之前做一个判断,验证当前的锁是不是自己加的锁, 那 value 应该是存当前线程的标识或者uuid
String key = "coupon_66"
String value = Thread.currentThread().getId()
if(setnx(key,value) == 1){
expire(key,30,TimeUnit.MILLISECONDS)
try {
//做对应的业务逻辑
} finally {
//删除锁,判断是否是当前线程加的
if(get(key).equals(value)){
//还存在时间间隔
del(key)
}
}
}else{
//睡眠100毫秒,然后自旋调用本方法
}
进一步细化误删
当线程A获取到正常值时,返回带代码中判断期间锁过期了,线程B刚好重新设置了新值,线程A那边有判断value是自己的标识,然后调用del方法,结果就是删除了新设置的线程B的值
核心还是判断和删除命令 不是原子性操作导致
总结
加锁+配置过期时间:保证原子性操作
解锁: 防止误删除、也要保证原子性操作
那如何解决呢?下集讲解
《小滴课堂-Redis6学习笔记》