悲观锁和乐观锁

1:什么是悲观锁、乐观锁?

   生活里有两种人,悲观的,乐观的。悲观锁也就是对应悲观锁,把事情总是往坏处想。乐观锁也就是生活中乐观的人,把事情往乐观方面想。

 

2:悲观锁

    悲观锁,总是把事情往坏处想。比如获取数据的时候,总担心别人修改自己要获取的数据。所以:悲观锁就是:共享资源每次只能给一个线程使用,其他线程阻塞,直到该线程使用完,才把资源让给其它线程。

   像 java 的 synchronized就是悲观锁

 

3:乐观锁

     乐观锁,总是把事情往乐观处想,每次去拿数据都觉得别人不会修改,所以不会上锁,但是在更新的时候,会判断一下此期间有没有人去修改数据。可以使用版本号和CAS算法实现。乐观锁适用于读操作,这样可以提高吞吐量。

    想数据库提供的 write_condition机制,其实都是提供乐观锁。

   在  java.util.concurrent.atomic 包下的原子变量类就是使用乐观锁的一种CAS方式实现。

 

4:乐观锁、悲观锁的使用场景?

    乐观锁适用于读的场景:提高吞吐量

    悲观锁适用于写的场景:减少retry,提高性能

 

5:乐观锁的实现方式?

    1)版本号限制

         具体实现:在数据库加一个字段:version,每次读取+1,如果本地读取的值为2,在更新的时候为2,则可以更新,若不为2,则不允许更新。

    2)CAS算法

         compare and swap(比较和交换),是一种有名的无锁算法。即在不使用锁的情况下实现多线程之间的变量同步。

        CAS算法,涉及三个变量的操作:

         1):需要读取内存值:V

         2):进行比较的值:A

         3):拟写入的值:B

     当且仅当V的值和A的值相同,才允许使用原子的方式用新值:B替换掉V的值,否则什么也不做。一般情况下CAS是不断重试的。

 

 

6:乐观锁的缺点?

   1):ABA问题。比如一开始读取的内存值V=A,当检查准备更新的时候发现还是A,那我CAS算法认为值没有被改动过,这是不对的。中间可能被改成B,之后再被改成A。JDK1.5解决了此问题:AtomicStampedReference 类提供了compareAndSet方法,检查当前引用是否等于预期引用,检查当前标志是否预期标志,如果全部都是预期的,则更新。

 

   2):循环开销大。自轩CAS算法在失败后会不断重试,如果一直失败,那么对于JVM来说是消耗巨大的。

 

   3):只能保证一个共享变量的原子操作。

 

7:CAS和Synchronized使用场景?

     1)CAS:多读情况(冲突比较少)

     2)synchroized:多写情况(冲突场景较少)

  

 

posted @ 2020-06-29 15:28  QH.Thomas  阅读(153)  评论(0编辑  收藏  举报