简单redis锁实现(思考问题)
@Autowired
private StringRedisTemplate stringRedisTemplate;
public String testRedisLock() {
String lockKey = "lock:product:1";
String clientId = UUID.randomUUID().toString();
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, clientId, 30, TimeUnit.SECONDS);
if (!result)
return "error";
try {
//TODO
} finally {
if (clientId.equals(stringRedisTemplate.opsForValue().get(lockKey))) {
stringRedisTemplate.delete(lockKey);
}
}
return "ok";
}
常规实现
@Autowired
private Redisson redisson;
@Autowired
private StringRedisTemplate stringRedisTemplate;
public String testRedissonLock() {
String lockKey = "lock:product:1";
//获取锁对象
RLock redissonLock = redisson.getLock(lockKey);
//加分布式锁
redissonLock.lock();
try {
int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
if (stock > 0) {
int realStock = stock - 1;
stringRedisTemplate.opsForValue().set("stock", realStock + "");
System.out.println("扣减成功,剩余库存:" + realStock);
} else {
System.out.println("扣减失败,库存不足");
}
} finally {
//解锁
redissonLock.unlock();
}
return "ok";
}
Redisson 加锁原理
Redisson 源码分析
redissonLock.lock();
redissonLock.lock();
redissonLock.lockInterruptibly();
redissonLock.lockInterruptibly(-1L, (TimeUnit)null);
Long ttl = redissonLock.tryAcquire(leaseTime, unit, threadId);
redissonLock.tryAcquireAsync(leaseTime, unit, threadId)
RFuture<Long> ttlRemainingFuture = redissonLock.tryLockInnerAsync(redissonLock.commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);
<T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
this.internalLockLeaseTime = unit.toMillis(leaseTime);
return this.commandExecutor.evalWriteAsync(this.getName(),
LongCodec.INSTANCE,
command,
("if (redis.call('exists', KEYS[1]) == 0) then " +
"redis.call('hset', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
"return redis.call('pttl', KEYS[1]);"),
Collections.singletonList(this.getName()),
new Object[]{this.internalLockLeaseTime, this.getLockName(threadId)}
);
}