提一下:
单体应用是一个jvm也就是n对一,单体应用使用普通的锁就可以解决,如可重入锁(ReentrantLock,synchronized等)
分布式应用是多个jvm也就n对多,就必须使用分布式锁来解决,如zookeeper实现的分布式锁或者redis实现的分布式锁
本期讲redis分布式锁:
public void testLock() {
// 1. 从redis中获取锁,setnx
String uuid = UUID.randomUUID().toString();
Boolean lock = this.redisTemplate.opsForValue()
.setIfAbsent("lock", uuid, 2, TimeUnit.SECONDS);
if (lock) {
// 查询redis中的num值
String value = this.redisTemplate.opsForValue().get("num");
// 没有该值return
if (StringUtils.isBlank(value)){
return ;
}
// 有值就转成成int
int num = Integer.parseInt(value);
// 把redis中的num值+1
this.redisTemplate.opsForValue().set("num", String.valueOf(++num));
// 2. 释放锁 del
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
this.redisTemplate.execute(new DefaultRedisScript<>(script), Arrays.asList("lock"), Arrays.asList(uuid));
/*if (StringUtils.equals(redisTemplate.opsForValue().get("lock"), uuid)){
this.redisTemplate.delete("lock");
}*/
} else {
// 3. 每隔500毫秒回调一次,再次尝试获取锁
try {
Thread.sleep(500);
testLock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:
-
互斥性。在任意时刻,只有一个客户端能持有锁。
-
不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
-
解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
-
加锁和解锁必须具有原子性。