高并发场景下秒杀下单超卖问题
模拟扣减库存方法(JVM级别锁,分布式环境下异常)
@RequestMapping("/deduct_stock")public String deductStock(){synchronized (this) {int stock=Integer.parseInt((stringRedisTemplate.opsForValue().get("stock")));//jedis.get("stock");if(stock>0){int realStock=stock-1;stringRedisTemplate.opsForValue().set("stock",realStock+"");//jedis.set(key,value);System.out.println("扣减成功,剩余库存:"+realStock);}else{System.out.println("扣减失败,库存不足");}}return "end";}
1.使用redis的setnx实现分布式锁
@RequestMapping("/deduct_stock")public String deductStock(){String lockKey="product_101"Boolean result=stringRedisTemplate.opsForValue().setIfAbsent(lockKey,"zz");if(!result) {return "error_code";}try {int stock = Integer.parseInt((stringRedisTemplate.opsForValue().get("stock")));//jedis.get("stock");if (stock > 0) {int realStock = stock - 1;stringRedisTemplate.opsForValue().set("stock", realStock + "");//jedis.set(key,value);System.out.println("扣减成功,剩余库存:" + realStock);} else {System.out.println("扣减失败,库存不足");}}finally {stringRedisTemplate.delete(lockKey);//锁释放}return "end";}
问题:系统宕机finall未执行,则锁未释放
解决办法:设置超时时间
stringRedisTemplate.expire(lockKey,10, TimeUnit.SECONDS);
问题:设置完锁突然异常,未成功设置超时时间
解决办法:原子操作设置锁和超时时间
Boolean result=stringRedisTemplate.opsForValue().setIfAbsent(lockKey,"zz",10, TimeUnit.SECONDS);
问题:线程2删除了线程1的锁,锁失效
解决办法:只能删除clientId自身的锁
问题:锁判断、删除也需要原子执行
解决办法:锁续命
2.Redisson分布式锁方案
原理

