学习资料
【MySQL数据库教程天花板,mysql安装到mysql高级,强!硬!-哔哩哔哩】
【阿里巴巴Java开发手册】https://www.w3cschool.cn/alibaba_java
锁的不同角度分类
锁的分类图如下
从对待锁的态度划分:乐观锁、悲观锁
从对待锁的态度来看锁的话,可以将锁分成乐观锁和悲观锁,从名字中也可以看出这两种锁是两种看待
数据并发的思维方式
。需要注意的是,乐观锁和悲观锁并不是锁,而是锁的设计思想
。
悲观锁(Pessimistic Locking)
悲观锁是一种思想,顾名思义,就是很悲观,对数据被其他事务的修改持保守态度,会通过数据库自身的锁机制来实现,从而保证数据操作的排它性。
悲观锁总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会
阻塞
直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程
)。比如行锁、表锁等,读锁,写锁等,都是在做操作之前先上锁,当其他线程想要访问数据时,都需要阻塞挂起。Java中synchronized
和ReentrantLock
等独占锁就是悲观锁思想的实现。
悲观锁不适用的场景较多,它存在一些不足,因为悲观锁大多数情况下依靠数据库的锁机制来实现,以保证程序的并发访问性,同时这样对数据库性能开销影响也很大,特别是
长事务
而言,这样的开销往往无法承受
,这时就需要乐观锁。
乐观锁(Optimistic Locking)
乐观锁认为同一数据的并发操作不会总发生,属于小概率事件,不用每次都对数据上锁,但在更新的时候会判断一下在此期间别人有没有去更新这个数据,也就是
不采用数据库自身的锁机制,而是通过程序来实现
。在程序上,我们可以采用版本号机制
或者CAS机制
实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量
。在Java中java.util.concurrent.atomic
包下的原子变量类就是使用了乐观锁的一种实现方式:CAS实现的。
两种锁的适用场景
从这两种锁的设计思想中,我们总结一下乐观锁和悲观锁的适用场景:
1、乐观锁
适合读操作多
的场景,相对来说写的操作比较少。它的优点在于程序实现
,不存在死锁
问题,不过适用场景也会相对乐观,因为它阻止不了除程序以外的数据库操作。
2、悲观锁
适合写操作多
的场景,因为写的操作具有排它性
。采用悲观锁的方式,可以在数据库层面阻止其他事务对数据的操作权限,防止读 - 写
和写 - 写
的冲突。