1.不加锁版本
@Test
public void testLock1() {
// 从redis获取库存数量
int stock = Integer.parseInt(String.valueOf(redisTemplate.opsForValue().get("stock")));
// 如果库存数量大于0
if (stock > 0) {
int realStock = stock -1;
redisTemplate.opsForValue().set("stock", realStock + "");
System.out.println("扣减成功,剩余库存:" + realStock);
} else { // 如果库存数量小于0
System.out.println("扣减失败,库存不足!");
}
}
用的是springbootTest进行模拟的普通秒杀扣减库存,从redis扣减库存
1.1测试代码
@Test
public void testLock() throws InterruptedException {
redisTemplate.opsForValue().set("stock", 100 + "");
CountDownLatch countDownLatch = new CountDownLatch(1000);
ExecutorService executor = Executors.newFixedThreadPool(1000);
for(int i = 0; i < 1000; i++) {
executor.execute(() -> {
try {
testLock1();
} catch (Exception e) {
log.error("异常", e);
} finally {
countDownLatch.countDown();
}
});
}
// 等待所有线程执行完毕
countDownLatch.await();
// 关闭线程池
executor.shutdown();
int stock = Integer.parseInt(String.valueOf(redisTemplate.opsForValue().get("stock")));
System.err.println("::::::剩余库存:::::::" +stock);
}
可以看到执行了1000次还显示库存是96呢,因为多个线程去查redis的时候可能都是100,然后都执行100-1,他同时变成99,导致数据错误;
1.2使用Redisson枷锁的方式
@Test
public void testLock2() {
String lockKey = "lockKey";
// 获取到redisson锁对象
RLock redissonLock = redissonClient.getLock(lockKey);
try {
redissonLock.lock();
// 从redis获取库存数量
int stock = Integer.parseInt(String.valueOf(redisTemplate.opsForValue().get("stock")));
// 如果库存数量大于0
if (stock > 0) {
int realStock = stock -1;
redisTemplate.opsForValue().set("stock", realStock + "");
System.out.println("扣减成功,剩余库存:" + realStock);
} else { // 如果库存数量小于0
System.out.println("扣减失败,库存不足!");
}
} finally { // 防止异常导致锁无法释放!!!
redissonLock.unlock();
}
}
需要配置redisson客户端和引入redisson依赖才能用哦!!!
测试代码
@Test
public void testLock() throws InterruptedException {
redisTemplate.opsForValue().set("stock", 100 + "");
CountDownLatch countDownLatch = new CountDownLatch(1000);
ExecutorService executor = Executors.newFixedThreadPool(1000);
for(int i = 0; i < 1000; i++) {
executor.execute(() -> {
try {
testLock2();
} catch (Exception e) {
log.error("异常", e);
} finally {
countDownLatch.countDown();
}
});
}
// 等待所有线程执行完毕
countDownLatch.await();
// 关闭线程池
executor.shutdown();
int stock = Integer.parseInt(String.valueOf(redisTemplate.opsForValue().get("stock")));
System.err.println("::::::剩余库存:::::::" +stock);
}
非常优雅的执行完毕把库存扣减为0