乐观锁和悲观锁

  乐观锁和悲观锁是属于一种思想,不是具体的锁。

 

悲观锁(Pessimistic Lock):

  顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。

  传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

  Java synchronized 就属于悲观锁的一种实现,每次线程要修改数据时都先获得锁,保证同一时刻只有一个线程能操作数据,其他线程则会被block。

 

  悲观并锁实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。

  但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;

  另外,在只读型事务处理中由于不会产生冲突,也没必要使用锁,这样做只能增加系统负载,还有会降低了并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数

 

乐观锁(Optimistic Lock):

  顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,

  乐观锁适用于多读的应用类型,这样可以提高吞吐量。

  Java JUC中的atomic包就是乐观锁的一种实现,AtomicInteger 通过CAS(Compare And Set)操作实现线程安全的自增。

 

  乐观锁相信事务之间的数据竞争(data race)的概率是比较小的,因此尽可能直接做下去,直到提交的时候才去锁定,所以不会产生任何锁和死锁。

  乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。

 

乐观锁一般来说有以下2种方式:

  使用数据版本(Version)记录机制实现(最常用):即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。

  当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。

  当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。

 

  使用时间戳(timestamp):同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp)。

  和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。

 

posted @ 2018-05-22 19:26  __Meng  阅读(239)  评论(0编辑  收藏  举报