问题描述:
某电商平台, 首发一款新品手机, 每人限购 2 台, 预计会有 10W 的并发, 在该情况下, 如果扣减库存, 保证不会超卖
解决方案一
利用数据库锁机制, 对记录进行锁定, 再进行操作
- SELECT * from goods where ID =1 for update;
- UPDATE goods set stock = stock - 1;
利用排它锁将并行转化为串行操作, 但该方案的性能和用户体验较差
解决方案二
利用 Redis 实现分布式锁,
使用 setnx 命令 (在 key 不存在时, 创建并设置 value 返回 1,key 存在时, 会反回 0) 来获取锁, 在业务逻辑中, 我们可以通过这样的方案来操作
- Jedis client = jedisPool.getResource();
- while(client.setnx("lock",String.valueOf(System.currentTimeMillis())) == 0){
- Thread.sleep(10000);
- }
- //coding here
- client.del("lock")
方案二进阶
考虑到死锁问题, 即现成 A 获取锁后, 宕机了, 导致锁一直无法释放, 我们可以通过 get 命令获取锁的时间戳, 通过他进行超时判断, 并进行释放
- Long TIMEOUT_SECOUND = 120000L;
- Jedis client = jedisPool.getResource();
- while(client.setnx("lock",String.valueOf(System.currentTimeMillis())) == 0){
- Long lockTime = Long.valueOf(client.get("lock"));
- if (lockTime!=null && System.currentTimeMillis()> lockTime+TIMEOUT_SECOUND) {
- client.del("lock");
- }
- Thread.sleep(10000);
- }
- ...........................
- ...........................
- client.del("lock")
方案二加强
方案 2 的算法中, 为了确保在非超时情况下, 锁只能由有锁的线程进行释放, 可以在 value 的时间戳中, 拼上线程特征码
- Long TIMEOUT_SECOUND = 120000L;
- String featureCode = "machine01";
- Jedis client = jedisPool.getResource();
- while(client.setnx("lock",featureCode+":"+String.valueOf(System.currentTimeMillis())) == 0){
- Long lockTime = Long.valueOf(client.get("lock").substring(9));
- if (lockTime!=null && System.currentTimeMillis()> lockTime+TIMEOUT_SECOUND) {
- client.del("lock");
- }
- Thread.sleep(10000);
- }
- ...........................
- ...........................
- if (featureCode.equals(client.get("lock").substring(0, 8))) {
- client.del("lock");
- }
来源: http://www.bubuko.com/infodetail-3296336.html