前言
分布式锁是一种悲观锁
,至少要确保锁的实现同时满足以下四个条件:
-
互斥性
: 在任意时刻,只有一个客户端(进程)能持有锁。(UUID、重入锁) -
不会发生死锁
: 即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。(超时,临时节点) -
具有容错性
: 只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。(redis cluster) -
解铃还须系铃人
。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
问题:一旦加了分布式锁之后,对同一个商品(按商品加锁)的下单请求,会导致所有客户端都必须对同一个商品的库存锁key进行加锁。这样会导致对同一个商品的下单请求,就必须串行化,一个接一个的处理。
思考:在高并发场景下如何优化分布式锁的并发性能?
实现方式
如果大家了解ConcurrentHashMap的源码和底层原理,应该知道里面的核心思路,就是分段加锁!
- 把数据分成多段,每段是一个单独的锁,所以多个线程过来并发修改数据的时候,可以并发的修改不同段的数据。不至于说,同一时间只能有一个线程独占修改ConcurrentHashMap中的数据。
- Java 8中新增了一个LongAdder类,也是针对Java 7以前的AtomicLong进行的优化,解决的是CAS类操作在高并发场景下,使用乐观锁思路,会导致大量线程长时间重复循环。
- LongAdder中也是采用了类似的分段CAS操作,失败则自动迁移到下一个分段进行CAS的思路。
不足
- 首先,得对一个数据分段存储,一个库存字段本来好好的,现在要分为多个分段库存字段;
- 其次,在每次处理库存的时候,还得自己写随机算法,随机挑选一个分段来处理;
- 最后,如果某个分段中的数据不足了,你还得自动切换到下一个分段数据去处理。