我查了很多redis分布式锁都是通过jedisclient来实现的,因为springboot2.x默认连接客户端是lettuce,所以引用一个大佬用jedis写的锁修改下。
直接贴代码
1.接口类
public interface DistributedLock {
public static final long TIMEOUT_MILLIS = 30000;
public static final int RETRY_TIMES = 10;
public static final long SLEEP_MILLIS = 500;
public boolean lock(String key);
public boolean lock(String key, int retryTimes);
public boolean lock(String key, int retryTimes, long sleepMillis);
public boolean lock(String key, long expire);
public boolean lock(String key, long expire, int retryTimes);
public boolean lock(String key, long expire, int retryTimes, long sleepMillis);
public boolean releaseLock(String key);
}
复制代码
2.依然是接口
public abstract class AbstractDistributedLock implements DistributedLock {
@Override
public boolean lock(String key) {
return lock(key , TIMEOUT_MILLIS, RETRY_TIMES, SLEEP_MILLIS);
}
@Override
public boolean lock(String key, int retryTimes) {
return lock(key, TIMEOUT_MILLIS, retryTimes, SLEEP_MILLIS);
}
@Override
public boolean lock(String key, int retryTimes, long sleepMillis) {
return lock(key, TIMEOUT_MILLIS, retryTimes, sleepMillis);
}
@Override
public boolean lock(String key, long expire) {
return lock(key, expire, RETRY_TIMES, SLEEP_MILLIS);
}
@Override
public boolean lock(String key, long expire, int retryTimes) {
return lock(key, expire, retryTimes, SLEEP_MILLIS);
}
}复制代码
3.实现类
@Component
public class RedisDistributedLock extends AbstractDistributedLock {
@Autowired
@Resource(name="redisTemplateMaster")
private RedisTemplate<Object,Object> redisTemplate;
private final Logger logger = LoggerFactory.getLogger(RedisDistributedLock.class);
//private RedisTemplate<Object, Object> redisTemplate;
private ThreadLocal<String> lockFlag = new ThreadLocal<String>();
public static final String UNLOCK_LUA;
static {
StringBuilder sb = new StringBuilder();
sb.append("if redis.call(\"get\",KEYS[1]) == ARGV[1] ");
sb.append("then ");
sb.append(" return redis.call(\"del\",KEYS[1]) ");
sb.append("else ");
sb.append(" return 0 ");
sb.append("end ");
UNLOCK_LUA = sb.toString();
}
public RedisDistributedLock() {
super();
}
// public RedisDistributedLock(RedisTemplate<Object, Object> redisTemplate) {
// super();
// this.redisTemplate = redisTemplate;
// }
@Override
public boolean lock(String key, long expire, int retryTimes, long sleepMillis) {
boolean result = setRedis(key, expire);
// 如果获取锁失败,按照传入的重试次数进行重试
while((!result) && retryTimes-- > 0){
try {
logger.debug("lock failed, retrying..." + retryTimes);
Thread.sleep(sleepMillis);
} catch (InterruptedException e) {
return false;
}
result = setRedis(key , expire);
}
return result;
}
private boolean setRedis(final String key, final long expire ) {
try{
RedisCallback<Boolean> callback = (connection) -> {
String uuid = UUID.randomUUID().toString();
lockFlag.set(uuid);
return connection.set(key.getBytes(Charset.forName("UTF-8")), uuid.getBytes(Charset.forName("UTF-8")), Expiration.milliseconds(expire), RedisStringCommands.SetOption.SET_IF_ABSENT);
};
return (Boolean)redisTemplate.execute(callback);
} catch (Exception e) {
logger.error("redis lock error.", e);
}
return false;
}
@Override
public boolean releaseLock(String key) {
// 释放锁的时候,有可能因为持锁之后方法执行时间大于锁的有效期,此时有可能已经被另外一个线程持有锁,所以不能直接删除
try {
RedisCallback<Boolean> callback = (connection) -> {
String value = lockFlag.get();
return connection.eval(UNLOCK_LUA.getBytes(), ReturnType.BOOLEAN ,1, key.getBytes(Charset.forName("UTF-8")), value.getBytes(Charset.forName("UTF-8")));
};
return (Boolean)redisTemplate.execute(callback);
} catch (Exception e) {
logger.error("release lock occured an exception", e);
} finally {
// 清除掉ThreadLocal中的数据,避免内存溢出
lockFlag.remove();
}
return false;
}
}
复制代码
转载于:https://juejin.im/post/5c8cb043e51d4528641bdefb