原文链接:https://www.jianshu.com/p/8cc44d008177
使用redis的SET resource-name anystring NX EX max-lock-time 方式,用于分布式锁
实现原理
命令 SET resource-name anystring NX EX max-lock-time 是一种在 Redis 中实现锁的简单方法。
客户端执行以上的命令:
- 如果服务器返回 OK ,那么这个客户端获得锁。
- 如果服务器返回 NIL ,那么客户端获取锁失败,可以在稍后再重试。
- 设置的过期时间到达之后,锁将自动释放。
实现优化
可以通过以下修改,让这个锁实现更健壮:
- 不使用固定的字符串作为键的值,而是设置一个不可猜测(non-guessable)的长随机字符串,作为口令串(token)。
- 不使用 DEL 命令来释放锁,而是发送一个 Lua 脚本,这个脚本只在客户端传入的值和键的口令串相匹配时,才对键进行删除。
这两个改动可以防止持有过期锁的客户端误删现有锁的情况出现。
使用评价
参考实现的代码功能已经实现了,详见https://www.jianshu.com/p/8cc44d008177
但没有实现java的java.util.concurrent.locks.Lock接口,不方便以后更改实现或者进行扩展。
如果要集成到系统中使用,建议使用代理模式进行优化,将参考的RedisLock类作为RedisLockAdapter,实际的RedisLock实现代码如下:
public class RedisLock implements Lock {
private RedisLockAdapter redisLockAdapter;
/**
* @param redisLockAdapter
*/
public RedisLock(RedisLockAdapter redisLockAdapter) {
super();
this.redisLockAdapter = redisLockAdapter;
}
@Override
public void lock() {
redisLockAdapter.lock();
}
@Override
public void lockInterruptibly() throws InterruptedException {
// TODO method lockInterruptibly() is not implemented
}
@Override
public boolean tryLock() {
return redisLockAdapter.tryLock();
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
// TODO method tryLock(time, unit) is not implemented
return false;
}
@Override
public void unlock() {
redisLockAdapter.unlock();
}
@Override
public Condition newCondition() {
// TODO method newCondition() is not implemented
return null;
}
}
扩展阅读
另外,也研究了下Redis官方推荐的Redisson框架
整合参考资料:https://yq.aliyun.com/articles/554753
功能的确很强大:
- 支持Redis部署的各种模式
- 提供了很多jdk标准接口的实现
但Redisson的配置不兼容spring-data-redis,侵入性太强,非常不优雅。