您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > JAVA

Java性能 -- CAS乐观锁

时间:2019-09-18 09:29:54  来源:  作者:
Java性能 -- CAS乐观锁

 

synchronized / Lock / CAS

  1. synchronized和Lock实现的同步锁机制,都属于悲观锁,而CAS属于乐观锁
  2. 悲观锁在高并发的场景下,激烈的锁竞争会造成线程阻塞,而大量阻塞线程会导致系统的上下文切换,增加系统的性能开销

乐观锁

  1. 乐观锁:在操作共享资源时,总是抱着乐观的态度进行,认为自己能够完成操作
  2. 但实际上,当多个线程同时操作一个共享资源时,只有一个线程会成功,失败的线程不会被挂起,仅仅只是返回
  3. 乐观锁相比于悲观锁来说,不会带来死锁、饥饿等活性故障问题,线程间的相互影响也远远比悲观锁要小
  • 乐观锁没有因竞争而造成的系统上下文切换,所以在性能上更胜一筹

实现原理

  1. CAS是实现乐观锁的核心算法,包含3个参数:V(需要更新的变量),E(预期值)、N(最新值)
  2. 只有V等于E时,V才会被设置为N
  3. 如果V不等于E了,说明其它线程已经更新了V,此时该线程不做操作,返回V的真实值

CAS实现原子操作

AtomicInteger是基于CAS实现的一个线程安全的整型类,Unsafe调用CPU底层指令实现原子操作

// JAVA.util.concurrent.atomic.AtomicInteger
public final int getAndIncrement() {
 return unsafe.getAndAddInt(this, valueOffset, 1);
}
public final int getAndDecrement() {
 return unsafe.getAndAddInt(this, valueOffset, -1);
}
// sun.misc.Unsafe
public final int getAndAddInt(Object o, long offset, int delta) {
 int v;
 do {
 v = getIntVolatile(o, offset);
 } while (!compareAndSwapInt(o, offset, v, v + delta));
 return v;
}
public native int getIntVolatile(Object o, long offset);
public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);

处理器实现原子操作

  1. CAS是调用处理器底层指令来实现原子操作的
  2. 处理器和物理内存之间的通信速度要远低于处理器间的处理速度,所以处理器有自己的内部缓存(L1/L2/L3)
  3. 服务器通常为多处理器,并且处理器是多核的,每个处理器维护了一块字节的缓存存,每个内核也维护了一块字节的缓存
  • 此时在多线程并发就会存在缓存不一致的问题,从而导致数据不一致
  1. 处理器提供了总线锁定缓存锁定两种机制来保证复杂内存操作的原子性
  • 总线锁定
  • 当处理器要操作一个共享变量时,会在总线上会发出一个Lock信号,此时其它处理器就不能操作共享变量了
  • 总线锁定在阻塞其他处理器获取该共享变量的操作请求时,也可能会导致大量阻塞,从而增加系统的性能开销
  • 缓存锁定(后来出现)
  • 当某个处理器对缓存中的共享变量进行了操作,就会通知其他处理器放弃存储或者重新读取该共享变量
  • 目前最新的处理器都支持缓存锁定机制
Java性能 -- CAS乐观锁

 

 

优化CAS乐观锁

  1. 乐观锁在并发性能上要优于悲观锁
  • 但在写大于读的操作场景下,CAS失败的可能性增大,如果循环CAS,会长时间占用CPU
  • 例如上面的AtomicInteger#getAndIncrement
  1. JDK 1.8中,提供了新的原子类LongAdder
  • LongAdder在高并发场景下会比AtomicInteger和AtomicLong的性能更好,代价是消耗更多的内存空间
  • 核心思想:空间换时间
  • 实现原理:降低操作共享变量的并发数
  • LongAdder内部由一个base变量和一个cell[]数组组成
  • 当只有一个写线程(没有竞争
  • LongAdder会直接使用base变量作为原子操作变量,通过CAS操作修改base变量
  • 当有多个写线程(存在竞争
  • 除了占用base变量的一个写线程外,其他写线程的value值会分散到cell数组中
  • 不同线程会命中到数组的不同槽中,各个线程只对自己槽中的value进行CAS操作
  • value=base+∑ni=0Cell[i]
  • LongAdder在操作后的返回值只是一个近似准确的值,但最终返回的是一个准确的值
  • LongAdder不适合实时性要求较高的场景

性能对比

 

Java性能 -- CAS乐观锁

 

 

  1. 读大于写,读写锁ReentrantReadWriteLock、读写锁StampedLock、乐观锁LongAdder的性能最好
  2. 写大于读,乐观锁的性能最好,其他四种锁的性能差不多
  3. 读约等于写,两种读写锁和乐观锁的性能要优于synchronized和Lock

小结

  1. 乐观锁的常见使用场景:数据库更新
  • 为每条数据定义一个版本号,在更新前获取版本号,在更新数据时,再判断版本号是否被更新过,如果没有才更新数据
  1. CAS乐观锁的使用比较受限,因为乐观锁只能保证单个变量操作的原子性
  2. CAS乐观锁在高并发写大于读的场景下
  • 大部分线程的原子操作会失败,失败后的线程将不断重试CAS原子操作,导致大量线程长时间占用CPU资源
  • JDK 1.8中,新增了原子类LongAdder,采用空间换时间的思路解决了这个问题,但实时性不高


Tags:Java CAS乐观锁   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
synchronized / Lock / CAS synchronized和Lock实现的同步锁机制,都属于悲观锁,而CAS属于乐观锁 悲观锁在高并发的场景下,激烈的锁竞争会造成线程阻塞,而大量阻塞线程会导致系...【详细内容】
2019-09-18  Tags: Java CAS乐观锁  点击:(226)  评论:(0)  加入收藏
▌简易百科推荐
面向对象的特征之一封装 面向对象的特征之二继承 方法重写(override/overWrite) 方法的重载(overload)和重写(override)的区别: 面向对象特征之三:多态 Instanceof关键字...【详细内容】
2021-12-28  顶顶架构师    Tags:面向对象   点击:(2)  评论:(0)  加入收藏
一、Redis使用过程中一些小的注意点1、不要把Redis当成数据库来使用二、Arrays.asList常见失误需求:把数组转成list集合去处理。方法:Arrays.asList 或者 Java8的stream流式处...【详细内容】
2021-12-27  CF07    Tags:Java   点击:(3)  评论:(0)  加入收藏
文章目录 如何理解面向对象编程? JDK 和 JRE 有什么区别? 如何理解Java中封装,继承、多态特性? 如何理解Java中的字节码对象? 你是如何理解Java中的泛型的? 说说泛型应用...【详细内容】
2021-12-24  Java架构师之路    Tags:JAVA   点击:(5)  评论:(0)  加入收藏
大家好!我是老码农,一个喜欢技术、爱分享的同学,从今天开始和大家持续分享JVM调优方面的经验。JVM调优是个大话题,涉及的知识点很庞大 Java内存模型 垃圾回收机制 各种工具使用 ...【详细内容】
2021-12-23  小码匠和老码农    Tags:JVM调优   点击:(12)  评论:(0)  加入收藏
前言JDBC访问Postgresql的jsonb类型字段当然可以使用Postgresql jdbc驱动中提供的PGobject,但是这样在需要兼容多种数据库的系统开发中显得不那么通用,需要特殊处理。本文介绍...【详细内容】
2021-12-23  dingle    Tags:JDBC   点击:(13)  评论:(0)  加入收藏
Java与Lua相互调用案例比较少,因此项目使用需要做详细的性能测试,本内容只做粗略测试。目前已完成初版Lua-Java调用框架开发,后期有时间准备把框架进行抽象,并开源出来,感兴趣的...【详细内容】
2021-12-23  JAVA小白    Tags:Java   点击:(11)  评论:(0)  加入收藏
Java从版本5开始,在 java.util.concurrent.locks包内给我们提供了除了synchronized关键字以外的几个新的锁功能的实现,ReentrantLock就是其中的一个。但是这并不意味着我们可...【详细内容】
2021-12-17  小西学JAVA    Tags:JAVA并发   点击:(11)  评论:(0)  加入收藏
一、概述final是Java关键字中最常见之一,表示“最终的,不可更改”之意,在Java中也正是这个意思。有final修饰的内容,就会变得与众不同,它们会变成终极存在,其内容成为固定的存在。...【详细内容】
2021-12-15  唯一浩哥    Tags:Java基础   点击:(17)  评论:(0)  加入收藏
1、问题描述关于java中的日志管理logback,去年写过关于logback介绍的文章,这次项目中又优化了下,记录下,希望能帮到需要的朋友。2、解决方案这次其实是碰到了一个问题,一般的情况...【详细内容】
2021-12-15  软件老王    Tags:logback   点击:(19)  评论:(0)  加入收藏
本篇文章我们以AtomicInteger为例子,主要讲解下CAS(Compare And Swap)功能是如何在AtomicInteger中使用的,以及提供CAS功能的Unsafe对象。我们先从一个例子开始吧。假设现在我们...【详细内容】
2021-12-14  小西学JAVA    Tags:JAVA   点击:(22)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条