他总忘不了那样的日子,一个先令就能买到十三只上好的牡蛎。
这一次记录一点并发编程方面的内容——锁机制,也是在某一次课程中听到的。这是一个我之前毫无了解的概念,而并发编程也一直是我不敢触碰的高深知识。今天终于决定踏出第一步。
参考资料:
锁从宏观上分类,分为悲观锁与乐观锁。
乐观锁
乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作。
java中的乐观锁基本都是通过CAS操作实现的,CAS是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败。
悲观锁
悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会block直到拿到锁。
java中的悲观锁就是Synchronized,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到,才会转换为悲观锁,如RetreenLock。
锁的重量级别是:偏向锁-> 轻量级锁、自旋锁-> 重量级锁
偏向锁
偏向锁的目标是,减少无竞争且只有一个线程使用锁的情况下,使用轻量级锁产生的性能消耗。
“偏向”的意思是,偏向锁假定将来只有第一个申请锁的线程会使用锁(不会有任何线程再来申请锁)
轻量级锁
轻量级锁的目标是,减少无实际竞争情况下,使用重量级锁产生的性能消耗
自旋锁
首先,内核态与用户态的切换上不容易优化。但通过自旋锁,可以减少线程阻塞造成的线程切换(包括挂起线程和恢复线程)。
- 当前线程竞争锁失败时,打算阻塞自己;
- 不直接阻塞自己,而是自旋(空等待,比如一个空的有限for循环)一会;
- 在自旋的同时重新竞争锁;
- 如果自旋结束前获得了锁,那么锁获取成功;否则,自旋结束后阻塞自己 ;
可以看到,自旋锁是需要占用CPU的,因此在单核处理器、或是线程数多而核数少的情况下,很可能会造成无用的浪费。
重量级锁
当有两个及以上的线程争用同一个锁,那么轻量级锁就不再有效,要膨胀为重量级锁。
脱离业务场景而单纯去理解它们着实有难度,而写下这句话的时候又突然觉得自己好没有上进心。害,那就尽快掌握吧。
over~
网友评论