Java 乐观锁和悲观锁

乐观锁和悲观锁的区别?

简单来说,乐观锁就是假设拿数据的都不会修改,所以读不加锁,写入的时候才加锁,去判断读取之后有没有被更新。而悲观锁是假设每次读数据都会修改,所以在读的时候就加锁,一个线程使用的时候,其它线程都阻塞。

乐观锁适合多读场景,悲观锁适合多写场景。

synchronized和ReentrantLock都是悲观锁。

乐观锁常见的实现方式?

  1. 版本号机制
    以数据库为例,给数据一个版本号字段,需要更新的话将读出的版本号增加,然后写入时比对版本号,如果表中的版本号小于要写入的版本号,就可以写入,否则就是被其他人修改了,就不允许写入更新,需要重新读取。

  2. CAS 比较与交换,无锁算法,非阻塞同步
    简单来说,就是写入的时候比较目标值是否等于读出的值,如果等于就更新为新的值,否则不做任何操作,一般情况下是一个自旋操作,即不断的重试。

CAS的缺点?

  1. ABA问题
    就是如果在读出A值后,其它线程将其修改为B,又修改回A,那么会被误认为未修改而直接更新。
  2. 循环时间长开销大
    自旋CAS(也就是不成功就一直循环执行直到成功)如果长时间不成功,会给CPU带来非常大的执行开销。
  3. 只能保证一个共享变量的原子操作
    CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时 CAS 无效。

CAS与synchronized的使用情景?

简单的来说CAS适用于写比较少的情况下(多读场景,冲突一般较少),synchronized适用于写比较多的情况下(多写场景,冲突一般较多)。

暂无评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

验证码已失效,请刷新验证码