Redis实现分布式锁优点:redis单线程(通过队列将并发变成串行,同一刻只有一个操作可以执行),有getset, setnx(set if not exist)等便于实现的方法
问题:
1. 简单的get & set方法为何不能实现:并发情况下会有锁竞争。参考http://blog.csdn.net/ugg/article/details/41894947
Redis实现分布式所需要注意的点:
1. 尽量减少锁内处理流程,避免在处理过程锁失效。
2.要有锁过期机制,避免其他客户端无法获取锁时,造成死锁崩溃。
3.尽量使得 锁内流程处理时间 < 锁过期时间(value值) < 锁失效时间(key的expire)
(这是锁的意义:锁应该用时获取,不用时释放,避免等待锁自己的超时释放。)
Java&Jedis实现参考:
public DistributedLock acquireLock(String key, long timeout) {
if (timeout > 10 * 1000) {
throw new IllegalArgumentException("Lock time can not be more than 10 seconds.");
}
StringRedisTemplate stringRedisTemplate = RedisTemplateContext.getStringRedisTemplate(RedisHosts.SINGLE_FIRST);
BoundValueOperations<String, String> lockOpt = stringRedisTemplate.boundValueOps(key);
long currentTime = System.currentTimeMillis();
long nextLockTimeout = currentTime + timeout + 1;
DistributedLock lockResult = new DistributedLock();
lockResult.setKey(key);
lockResult.setAcqLockTime(nextLockTimeout);
lockResult.setAcquiredSucc(false);
if (lockOpt.setIfAbsent(String.valueOf(nextLockTimeout))) {
lockOpt.expire(10, TimeUnit.MINUTES);
lockResult.setAcquiredSucc(true);
return lockResult;
}
String lockTimeInRedis = lockOpt.get();
if (lockTimeInRedis == null || currentTime > Long.parseLong(lockTimeInRedis)) {
String preLockTime = lockOpt.getAndSet(String.valueOf(nextLockTimeout));
if (isTimeEqual(lockTimeInRedis, preLockTime)) { //此处对比,避免getset期间有其它对象获取到锁
lockOpt.expire(10, TimeUnit.MINUTES);
lockResult.setAcquiredSucc(true);
return lockResult;
}
}
return lockResult;
}