在Redis中,乐观锁通常是通过使用 WATCH、MULTI 、EXEC和DISCARD命令实现的。这种乐观锁机制允许客户端在执行事务期间监视一个或多个键,并且只有在事务执行期间没有其他客户端修改被监视的键时,才会执行事务。
应用场景:
- 库存控制:在电商系统中,通过乐观锁控制商品库存的增减操作,避免超卖或超卖的情况发生。
- 秒杀系统:在秒杀活动中,通过乐观锁控制用户抢购商品的库存,确保活动期间库存不会超卖。
- 限流控制:通过乐观锁实现对某个资源的限流操作,可以控制请求的并发数量,保护系统免受突发高并发的影响。
使用案例:
下面是一个简单的伪代码,简单演示如何在 Redis 中实现乐观锁:
cpp
while(true){
// 监视键
WATCH key
// 开启事务
MULTI
// 事务中执行操作
GET key
SET key value
try{
// 提交事务
EXEC
}catch{
// 如果事务执行失败(被监视的键被其他客户端修改了),执行 DISCARD
DISCARD
}
}
使用jedis实现秒杀场景的demo,通过乐观锁控制用户抢购商品的库存,确保活动期间库存不会超卖
java
public class SecKillDemo {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
// 初始化商品库存
String productKey = "product:001";
jedis.set(productKey, "5");
String user = "user1";
while (true) {
try {
jedis.watch(productKey);
int remainingStock = Integer.parseInt(jedis.get(productKey));
if (remainingStock > 0) {
Transaction tx = jedis.multi();
tx.decr(productKey);
tx.exec();
System.out.println(user + " 秒杀成功,剩余库存: " + (remainingStock - 1));
} else {
System.out.println(user + " 秒杀失败,商品已售罄");
}
break;
} catch (JedisDataException e) {
System.out.println(user + " 秒杀失败,重新尝试秒杀");
} finally {
jedis.unwatch();
}
}
jedis.close();
}
}
注意:
在调用 exec()
方法后,会返回一个包含每个命令返回结果的列表,如果列表为空,则表示事务执行失败。当事务执行失败时,可以考虑让程序休眠一段时间后进行重试,而不是无限制地频繁重试,以避免耗尽系统资源导致栈内存溢出或其他问题。通过控制重试次数和重试间隔时间 ,可以有效地处理事务执行失败的情况,并降低系统负担(无限重试会导致栈内存溢出)。
ps:以下是我整理的java面试资料,密码是obht,感兴趣的可以看看。最后,创作不易,觉得写得不错的可以点点关注!