乐观锁与悲观锁的小研究

253 阅读2分钟

一、乐观锁

顾名思义为操作时很乐观,认为操作不会产生并发问题(不会有其它线程对数据进行修改),因此不会上锁。但是在更新时会判断其它线程在这之前有没有对数据进行修改,一般通过版本号机制、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 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。 ”这其实和乐观锁的冲突检查+数据更新的原理是一样的。

二、悲观锁

总是假设最坏的情况,每次取数据时都认为其他线程会修改,所以都会加(悲观)锁。一旦加锁,不同线程同时执行时,只能有一个线程执行,其他的线程在入口处等待,直到锁被释放。

悲观锁在MySQLJava有广泛的使用

  • MySQL的读锁、写锁、行锁等
  • Javasynchronized关键字

三、总结

读的多,冲突几率小,乐观锁
写的多,冲突几率大,悲观锁