Java 并发编程中有介绍CAS实现锁的机制,后面再看了一些编译原理方法的书,对锁的实现有一些基本了解。
提高并发减少上下文切换的方法:
- 无锁并发编程:按Hash算法取模分段,不同的线程处理不同段数据。
- CAS算法:CAS算法更新数据,无需加锁。
- 使用最少线程:尽量用少的线程,不要造成等待。
- 协程:在单线程里实现多任务的调度。
Java并发机制的底层实现
- Volatile:将当前处理器缓存行数据回写到系统内存,并让其他缓存失效。
- synchronized:同步代码块,锁定对象头。monitorenter和monitorexit指令。
- 原子操作:通过锁和循环CAS的方式来实现原子操作。
JVM内部实现了很多种锁机制,有偏向锁、轻量级锁和互斥锁。有意思的是除了偏向锁,JVM实现锁的方式都用了循环CAS,即当一个线程想进入同步块的时候使用循环CAS的方式来获取锁,当它退出同步块的时候使用循环CAS释放锁。
单应用部署可以通过Java锁现实线程同步,当部署微服务时,需要锁定库存量时就需要想其他办法,Redis CAS操作实现乐观锁。
Redis乐观锁工作机制:
watch指令在Redis事物中提供了CAS的行为。watch 命令会监视给定的每一个key,当exec时如果监视的任一个key自从调用watch后发生过变化,则整个事务会回滚,不执行任何动作。注意watch的key是对整个连接有效的,事务也一样。如果连接断开,监视和事务都会被自动清除。当然exec,discard,unwatch命令,及客户端连接关闭都会清除连接中的所有监视。还有,如果watch一个不稳定(有生命周期)的key并且此key自然过期,exec仍然会执行事务队列的指令。
实战应用:
当设计一个秒杀系统时候,为防止商品数量被超额购买,可以预先把库存数量加载到redis中,活动开始后服务端每次都通过Redis控制库存数量,同时使用watch命令实现CAS锁,如何Redis返回正常则走正常流程,如果否,则重试进入秒杀流程。通过Redis可以有效防止商品库存爆掉。
随想
我们在饿了么上面购买商品时候,涉及到支付,当我们购买一个商品后,因为某个原因没有支付,这时候订单会变成等待支付,这时候商品数量是应该减还是不减了。这个问题应该是一个产品问题,但是对应到代码层面我们会认为这就是悲观锁和乐观锁的设计区别。假定对系统数据流程要求很严格,可以直接使用悲观锁方式,直接先锁定数据,即库存数量减少,如果失败则回退库存,这样设计就会让很多用户因库存不够被排斥在外无法购买。乐观锁则只在支付完成后减库存,中间可以不断重试。支付的过程也是一个事务的过程,一般涉及2个步骤,预提交支付和最终确认支付,可能还涉及到支付余额不足的问题,都是在支付环节需要解决的问题。
参考:
https://www.jianshu.com/p/ae25eb3cfb5d
https://www.cnblogs.com/martinzhang/p/3415204.html