本文共 1142 字,大约阅读时间需要 3 分钟。
使用场景: 1、服务器采用分布式集群(多个tomcat)和公用的redis 2、业务场景:多个用户同时下单的高并发情况下,为了保证库存一致,避免超卖的情况,可以考虑在减库存的操作当中进行加锁操作 3、尝试加锁,如果加锁失败则等待一段时间重试;如果加锁成功,则拿当前购买金额和redis中的库存金额进行比较 4、如果大于库存金额,则提示用户当前库存金额不足,请重新下单 5、如果小于库存金额,则进行减库存操作 6、完成4/5操作后立即释放锁,并执行下面的业务操作(更新数据库库存,更新账户信息,记录流水,记录客户订单) 7、异常情况: (1)业务处理失败,数据回滚,则返回用户下单失败,并还原库存(同时对库存操作进行加锁,保持数据一致) (2)获取锁的线程超时,则抛出异常,返回给客户端下单超时 8、在生成产品时候,同时在redis中存储该产品的库存 使用redis实现的分布式锁: 首先设置每个获取锁的线程的超时时间,如果超过时间没有获取到锁则抛出超时异常;(锁等待超时,防止线程饥饿,永远没有入锁执行代码的机会 ) 如果在时间范围则一直尝试获取锁;执行下列操作: 1、通过jedis.setnx(key,value)命令,设置锁的有效时间(防止死锁) key存放的该产品的唯一标识 value存放的当前时间+超时时间 (注:set if Not eXist 保证多个线程同一时间请求时,只有一个线程能获得锁;类似zookeeper的新增一个节点) 2、result 成功获得锁返回 1,否则 返回0 3、其它没有获得锁的线程,不断进行重试: (1)判断锁是否正常释放 通过setnx(key,value)命令判断返回值是否为1 (2)判断锁是否已经超时 ①通过get(key)获取到当前存储的超时时间curTime ②判断当前时间是否超时,如果超时进行步骤③,未超时则 ③如果超时,则通过jedis的getset(key)命令,获取到当前key的旧值oldTime,并重新设置新的值即超时时间; ④并判断oldTIME和curTime是否相等,如果相等 则当前线程获得锁 ⑤没有获得锁,等待一段时间后,继续执行第(1)步操作 ⑥获取到锁,执行业务逻辑,finally释放锁 ⑦释放锁,使用jedis.del(key),并把锁的标志置为false (注:getset(key)是同步的,确保只有一个线程能获取到最原始的超时时间) 注意:里边牵涉到两个超时时间 1、锁等待超时,防止线程饥饿,永远没有入锁执行代码的机会 2、锁的超时时间,防止异常情况导致一个线程一直占有锁操作
具体代码实现参考:http://www.cnblogs.com/0201zcr/p/5942748.html