zoukankan      html  css  js  c++  java
  • 常用锁、乐观锁、悲观锁、cas

    参考:
    https://tech.meituan.com/2018/11/15/java-lock.html
    https://www.cnblogs.com/jyroy/p/11365935.html

    常用锁

    常用锁

    基于软件实现同步:(1)内部锁;(2)显示锁:ReentrantLock、读写锁
    基于硬件实现同步: CAS

    乐观锁和悲观锁原理

    乐观锁与悲观锁是一种广义上的概念,体现了看待线程同步的不同角度。
    对于同一个数据的并发操作,悲观锁认为自己在使用数据的时候一定有别的线程来修改数据,因此在获取数据的时候会先加锁,确保数据不会被别的线程修改。Java中,synchronized关键字中的重量锁和Lock的实现类都是悲观锁。
    乐观锁认为自己在使用数据时不会有别的线程修改数据,所以不会添加锁,只是在更新数据的时候去判断之前有没有别的线程更新了这个数据。如果这个数据没有被更新,当前线程将自己修改的数据成功写入。如果数据已经被其他线程更新,则根据不同的实现方式执行不同的操作(例如报错或者自动重试)。
    乐观锁在Java中是通过使用无锁编程来实现,最常采用的是CAS算法。

    CAS原理

    CAS全称 Compare And Swap(比较与交换),是一种无锁算法。在不使用锁(没有线程被阻塞)的情况下实现多线程之间的变量同步。
    CAS算法涉及到三个操作数:

    • 需要读写的内存值 V。
    • 进行比较的值 A。
    • 要写入的新值 B。
      当且仅当 V 的值等于 A 时,CAS通过原子方式用新值B来更新V的值(“比较+更新”整体是一个原子操作),否则不会执行任何操作。一般情况下,“更新”是一个不断重试的操作。
      CAS虽然很高效,但是它也存在三大问题:
    • ABA问题。CAS需要在操作值的时候检查内存值是否发生变化,没有发生变化才会更新内存值。但是如果内存值原来是A,后来变成了B,然后又变成了A,那么CAS进行检查时会发现值没有发生变化,但是实际上是有变化的。ABA问题的解决思路就是在变量前面添加版本号,每次变量更新的时候都把版本号加一,这样变化过程就从“A-B-A”变成了“1A-2B-3A”。JDK从1.5开始提供了AtomicStampedReference类来解决ABA问题,具体操作封装在compareAndSet()中。compareAndSet()首先检查当前引用和当前标志与预期引用和预期标志是否相等,如果都相等,则以原子方式将引用值和标志的值设置为给定的更新值。
    • 循环时间长开销大。CAS操作如果长时间不成功,会导致其一直自旋,给CPU带来非常大的开销。
    • 只能保证一个共享变量的原子操作。对一个共享变量执行操作时,CAS能够保证原子操作,但是对多个共享变量操作时,CAS是无法保证操作的原子性的。Java从1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,可以把多个变量放在一个对象里来进行CAS操作。

    乐观锁适合场景

    适合多读少写的场景,因为写的少,所以cas不会循环多次,且没有加锁导致线程阻塞上下文切换,效率较高。

  • 相关阅读:
    leetcode279. 完全平方数
    leetcode752. 打开转盘锁
    C++中new和delete来创建和释放动态数组
    创建vector<T>容器
    C++ vector初始化方式
    leetcode622. 设计循环队列
    c++ new
    leetcode138. 复制带随机指针的链表
    MySql服务器重启 || 修改mysql原始密码
    JS中的正则表达式
  • 原文地址:https://www.cnblogs.com/lllliuxiaoxia/p/15688013.html
Copyright © 2011-2022 走看看