一、乐观锁
顾名思义为操作时很乐观,认为操作不会产生并发问题(不会有其它线程对数据进行修改),因此不会上锁。但是在更新时会判断其它线程在这之前有没有对数据进行修改,一般通过版本号机制、CAS算法实现。
简单理解:这里的数据,别想太多,你尽管用,出问题了算我怂,即操作失败后事务回滚、提示。
版本号机制
- 取出记录时,获取当前
version - 更新时,带上这个
version - 执行更新时,
set version = newVersion where version = oldVersion - 如果
version不对,就更新失败
核心SQL:
update table
set name = 'Aron', version = version + 1
where id = #{id} and version = #{version};
CAS算法
乐观锁的另一种技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。
CAS
操作中包含三个操作数 :
- 需要读写的内存位置
V - 进行比较的预期原值
A - 拟写入的新值
B
如果内存位置V的值与预期原值A相匹配,那么处理器会自动将该位置值更新为新值B。否则处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前值)。
CAS 有效地说明了“ 我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。 ”这其实和乐观锁的冲突检查+数据更新的原理是一样的。
二、悲观锁
总是假设最坏的情况,每次取数据时都认为其他线程会修改,所以都会加(悲观)锁。一旦加锁,不同线程同时执行时,只能有一个线程执行,其他的线程在入口处等待,直到锁被释放。
悲观锁在MySQL、Java有广泛的使用
MySQL的读锁、写锁、行锁等Java的synchronized关键字
三、总结
读的多,冲突几率小,乐观锁
写的多,冲突几率大,悲观锁