使用场景:
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、锁的超时时间,防止异常情况导致一个线程一直占有锁操作
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