java的CAS之乐观锁与悲观锁

今天在复习ConcurrentHashMap实现线程安全时即(Synchronized+CAS),深入的再次复习了CAS(乐观锁),synchronized(悲观锁)的知识点。写下知识点以作为梳理。

什么是乐观锁

  1. 含义:所有的情况都会往好的方向发展。乐观锁在操作数据时非常乐观,认为不会有其它线程同时来修改数据,所以不会上锁。但是在更新数据时,会进行判断值是否被修改过,如果没有被修改则进行操作,否则放弃操作。乐观锁里面没有锁(lock)。

  2. CAS:CAS即比较与交换 ,它是乐观锁思想的一种实现方式。CAS有三个参数V(需要操作的内存地址),A(期望值),B(新的值),在进行更新操作时会判断V是否等于A (即判断这个值是否已经被其它的线程修改过),如果等于则将B值赋值给V并且返回true,否则不做操作。

    2.1. CAS在多线程的情况下:多个线程使用CAS对数据进行操作时,只有V=A的线程才能完成对V的赋值,返回true,其它失败的线程不会被挂起,而是会不断的进行循环操作(自旋->后面有解释)。所以,CAS在不使用lock 的情况下 ,也能察觉到其它线程对当前线程的影响。
    Tips: 许多CAS的操作是自旋的:如果操作不成功,会一直重试,直到操作成功(这也是它的缺点)。

    2.2 . CAS的原子操作:什么是原子——》即不可再进行分割。什么是原子性操作——》即一旦进行操作,则不能打断,直到操作完成。CAS的原子性操作是由硬件进行保障的。
    2 .3 . CAS的问题以及解决方法:
    (1)ABA问题:假如有两个线程,线程1与线程2。
    第一步, 线程1读取数据的值为A,
    第二步,线程2则去修改数据的值为B ,
    第三步,线程2修改回数据的值为A,
    第四步,线程1 使用CAS操作数据。
    在第四步中,因为数据值仍然A,所以CAS操作成功,这似乎没有什么变化,但是 如果是在其它的场景下呢?比如一个栈的栈顶中,对栈顶进行多次的操作后,值虽然相同但是它已经改变了。
    解决:添加一个版本号,每次对数据进行操作后,就进行+1操作,进行CAS的比较时,除了比较V与A是否相等,还要比较版本号是否相等。
    (2)自旋问题带来的效率降低问题:
    在高竞争的环境下带来高概率的并发冲突问题,会导致失败的线程一直进行循环比较。这导致CPU开销变大。
    解决: 可以做一个退出机制,当失败的次数达到一定时,就进行退出。

    (3) CAS只能保证一个变量的原子操作。这意味着CAS在有多个变量的情况下已经不能保证线程的安全的问题。
    解决:可以使用AtomicReference把多个变量放入一个对象中进行CAS操作。

什么是悲观锁

1,含义:认为情况都往最坏的情况进行发展。悲观锁在操作数据时,认为会有其它的线程来修改数据,所以它操作数据时会将数据锁住,等操作完成后,再解锁 。
2,synchronized 就是悲观锁思想的实现。

使用场景:

乐观锁 使用的场景一般是在并发冲突少、竞争不激烈中。在这种场景下乐观锁的效率要高于悲观锁,因为 悲观锁会锁住代码,其它的线程不能操作。同理,高并发下冲突概率上升,建议使用悲观锁。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值