问题一
一个线程如果遇到业务阻塞,在业务还没有处理完的时候,超过了时间释放了锁,当业务处理完了的时候,释放锁,那么这个锁可能是别的线程的锁,那么就会引发安全问题
package com.hbue.CLASS;
import com.hbue.RedisInterface.ILock;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class RedisLock implements ILock {
private String name ;
private StringRedisTemplate stringRedisTemplate ;
private final String LOCK_PREFIX = "lock:";
private static final String ID_PREFIX = UUID.randomUUID().toString() + "-";
public RedisLock(String name, StringRedisTemplate stringRedisTemplate) {
this.name = name;
this.stringRedisTemplate = stringRedisTemplate;
}
@Override
public Boolean tryLock(Long lockTime) {
//获取线程标识
String threadName = Thread.currentThread().getName();
Boolean isLock = stringRedisTemplate.opsForValue().setIfAbsent(LOCK_PREFIX+name, threadName , lockTime, TimeUnit.SECONDS);
return isLock;
}
@Override
public void unlock() {
//避免redis分布式锁发生的错误
String threadName = Thread.currentThread().getName();
String lockName = stringRedisTemplate.opsForValue().get(LOCK_PREFIX + name);
if (lockName != null && lockName.equals(threadName)) {
stringRedisTemplate.delete(LOCK_PREFIX + name);
}
}
}
也可以在key上加上UUID
问题二
判断锁与释放锁是两个动作,中间可能会存在阻塞问题,解决方式:Lua脚本
问题三
锁重入:在获取了锁之后又执行另一个方法,在另一个方法里面又获取同一把锁进行操作
普通redis实现分布式锁是在内部维护一个String类型的结构记录锁与线程,而使用Redisson实现可重入锁是在内部维护一个Hash结构记录锁与线程及其所对应的重入次数,内部方法加锁时就将重入次数加1,当内部方法调用Unlock方法时不会删除锁而是将记录的重入次数减1,当重入次数为0时就将其删除