美文网首页
悲观锁和乐观锁总结

悲观锁和乐观锁总结

作者: 2like99 | 来源:发表于2017-04-24 23:24 被阅读0次

概念

乐观锁也叫共享锁、读锁,事务T给对象A加了乐观锁,则其他事务还可以给对象A加乐观锁。但不能加被排他锁。也就是可以同时读数据,但读的过程中,不允许任何写。

悲观锁也叫排他锁、写锁,事务T给对象A加了悲观锁,则其他事务不可以给对象A加任何锁。也就是在写期间,不允许任何读、写操作。

实现

在数据库用select for update属于乐观锁,update/delete属于悲观锁。

在java中,同步块属于悲观锁。ReentrantReadWriteLock有ReadLock/WriteLock,分别实现乐观锁和悲观锁。注意:java的锁只对单个jvm有效。所以在集群环境下,必须借助数据库或者第三方组件(例如:zookeeper,redis)。

应用场景

减库存:库存为10,每一个订单库存减1。
分析:减库存分两个步骤:1.判断是否有库存(库存为0);2.如果有则减1,如果没有则返回。
并发环境下,存在两个问题:

  1. A/B两个用户同时判断库存都只剩一件,进行减1操作,产生超发。
  2. 同时进行对库存做减1操作,库存少减了1(例如库存10。两个进程同时来减1,A进程做stock=10-1,B进程也做stock=10-1,则库存变成了9,而不是期望的8)。
    假设库存是一个变量stock 。

** 方案1(悲观锁)**:判断stock 是否大于0前,先将变量加一把写锁,然后再判断。这样其他进程连判断语句都进不了。

private final ReadWriteLock lock = new ReentrantReadWriteLock();   
private final Lock w = lock.writeLock();  
    
w.lock();
if(stock  >0) stock --; 
else return false;

方案2(乐观锁):判断A是否大于0前,先将变量加一把读锁,判断成功准备写之前,将读锁升级为写锁。

private final ReadWriteLock lock = new ReentrantReadWriteLock();  
private final Lock r = lock.readLock();  

r.lock();
if(a>0) {
  w.lock(); 
  a--; 
}
else return false;

在集群环境下的方案:借助数据库的悲观锁和乐观锁。由于数据库的锁资源非常宝贵,为了增加系统的吞吐量,一般采用版本号的方案。

假设数据库表Stock,有两个字段num,version,初始<10,0>。

select * from Stock;  //这里并没有加锁
if(Stock.num>0) {
  ver = Stock.version;
  update Stock set num=num-1,version=version+1 where version = ver;
  if (影响的行数 == 1) {
     return true;
  } else {
    return false;
  }
} else {
   return false;
}

另外,可以将上述方案结合起来。在java端做一个库存是否为空的变量(静态),这样就避免在库存已经为0的情况下还去查数据库。

private final ReadWriteLock lock = new ReentrantReadWriteLock();   
private final Lock w = lock.writeLock();  
static boolean isZero = false;

r.lock();
if(!isZero) {
select * from Stock;  //这里并没有加锁
if(Stock.num>0) {
  ver = Stock.version;
  update Stock set num=num-1,version=version+1 where version = ver;
  if (影响的行数 == 1) {
    //判断是否还有库存并修改变量
    select count(1) cnt from Stock  where num = 0;
    w.lock();
    isZero  = true;
    w.unlock();
     return true;
  } else {
    return false;
  }
} else {
   return false;
}

这里简化了一个问题,库存是针对某件商品的,所以应该是一个Map的锁。如果直接针对Map加锁势必导致多个商品同时被加锁。可以使用:

  1. java.util.concurrent.ConcurrentHashMap 类;
  2. 利用ReentrantReadWriteLock实现一个ReadWriteMap。见网络。

相关文章

  • 乐观锁和悲观锁

    参考来源 深入理解乐观锁与悲观锁 乐观锁的一种实现方式——CAS mysql乐观锁总结和实践 乐观锁和悲观锁 悲观...

  • 看完你就知道的乐观锁和悲观锁

    看完你就知道的乐观锁和悲观锁 Java 锁之乐观锁和悲观锁 [TOC] Java 按照锁的实现分为乐观锁和悲观锁,...

  • 锁的概述

    乐观锁与悲观锁 悲观锁 乐观锁和悲观锁的概念出自数据库,但在java并发包中也引入和类似的概念(乐观锁/悲观锁是一...

  • 并发参数

    悲观锁与乐观锁 悲观锁 synchronized和ReentrantLock等独占锁就是悲观锁思想的实现乐观锁一般...

  • CAS 与原子操作

    乐观锁与悲观锁 锁可以从不同的角度分类。其中,乐观锁和悲观锁是一种分类方式。 乐观锁:乐观锁又称为“无锁”。乐观锁...

  • 04 番外(待补充AQS相关原理) Java多线程中的各种锁

    1 乐观锁 悲观锁 1.1 乐观锁 乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设...

  • Mysql锁

    按照使用方式,锁分为: 悲观锁 乐观锁 乐观锁 概念就不细讲了,乐观锁和悲观锁的区别是乐观锁是假设在修改数据之前,...

  • MySQL之乐观锁·MVCC

    一、 乐观锁 和 悲观锁 乐观锁 和 悲观锁 是实现并发操作的两种不同的 加锁思想,其中: 乐观锁 假设:操作能成...

  • 蚂蚁面试

    1、mysql乐观锁和悲观锁的区别? 乐观锁通过MVCC,版本实现,悲观锁select... for update...

  • 一文简介乐观锁和悲观锁

    悲观锁和乐观锁的概念 乐观锁和悲观锁在面试过程中是经常遇到的,那么什么是乐观锁什么是悲观锁呢?首先需要明确的是乐观...

网友评论

      本文标题:悲观锁和乐观锁总结

      本文链接:https://www.haomeiwen.com/subject/qgdmzttx.html