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

乐观锁和悲观锁

作者: 沐兮_d64c | 来源:发表于2019-05-27 11:43 被阅读0次

    1,乐观锁与悲观锁概念

    1)概念:两种不同的思想,为了解决并发场景下的数据竞争。不局限于语言和数据库。
    2)乐观锁:操作数据时,认为别人不会修改,所以不会加锁,只在更新数据时,先查询判断下别人是否修改了数据,是则放弃,否则继续操作。如版本号机制和CAS.
    3)悲观锁:操作时直接加锁数据,操作完成才释放,期间其他人不能修改数据。如synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。
    4)应用场景
    悲观锁:用于写入、更新比较多的场景。
    乐观锁:用于读取比较多,写入、更新比较少的场景

    2,版本号机制实现乐观锁

    1)版本号机制:为数据增加一个version字段,更新数据时,先读出version,提交时,判断真实的version是否和刚读出的version一致。
    2)数据更新流程。
    query old verifyCode;
    generate new VerifyCode;
    update tb_account set amount = ?, verify_code = ? where userId = ? and verify_code = ?;
    3)数据更新流程,通常和retry重试(如:guava-retrying)绑定。retry单元中,先query,然后执行update,失败则重试。

    3,CAS实现乐观锁

    1)compare and swap(比较与交换),需要与volatile配合保证线程安全。
    AtomicInteger:利用Unsafe的cas和volatile关键字保证线程安全。
    当且仅当内存值=expect值时,才将内存值更新为update。

    image.png
    2)ABA问题
    线程1读取时记录为A,线程2多次修改后记录仍为A,线程1进行CAS操作。
    使用AtomicStampedReference解决ABA问题。
    image.png
    image.png
    3)CAS自旋锁
    public class MySpinLock {
    
      //可以原子更新的对象引用。
      private AtomicReference<Thread> cas = new AtomicReference<Thread>();
      
      //尝试加锁
      public void tryLock() {
        Thread current = Thread.currentThread();
        // 利用CAS, 获取失败则进行自旋
        while (!cas.compareAndSet(null, current)) {
          // DO nothing
        }
      }
      
      //尝试解锁
      public void unlock() {
        Thread current = Thread.currentThread();
        cas.compareAndSet(current, null);
      }
    
    }
    

    相关文章

      网友评论

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

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