Java性能 -- CAS乐观锁
synchronized / Lock / CAS
- synchronized和Lock实现的同步锁机制,都属于悲观锁,而CAS属于乐观锁
- 悲观锁在高并发的场景下,激烈的锁竞争会造成线程阻塞,而大量阻塞线程会导致系统的上下文切换,增加系统的性能开销
乐观锁
- 乐观锁:在操作共享资源时,总是抱着乐观的态度进行,认为自己能够完成操作
- 但实际上,当多个线程同时操作一个共享资源时,只有一个线程会成功,失败的线程不会被挂起,仅仅只是返回
- 乐观锁相比于悲观锁来说,不会带来死锁、饥饿等活性故障问题,线程间的相互影响也远远比悲观锁要小
- 乐观锁没有因竞争而造成的系统上下文切换,所以在性能上更胜一筹
实现原理
- CAS是实现乐观锁的核心算法,包含3个参数:V(需要更新的变量),E(预期值)、N(最新值)
- 只有V等于E时,V才会被设置为N
- 如果V不等于E了,说明其它线程已经更新了V,此时该线程不做操作,返回V的真实值
CAS实现原子操作
AtomicInteger是基于CAS实现的一个线程安全的整型类,Unsafe调用CPU底层指令实现原子操作
1 |
// java.util.concurrent.atomic.AtomicInteger |
1 |
// sun.misc.Unsafe |
处理器实现原子操作
- CAS是调用处理器底层指令来实现原子操作的
- 处理器和物理内存之间的通信速度要远低于处理器间的处理速度,所以处理器有自己的内部缓存(L1/L2/L3)
- 服务器通常为多处理器,并且处理器是多核的,每个处理器维护了一块字节的缓存存,每个内核也维护了一块字节的缓存
- 此时在多线程并发就会存在缓存不一致的问题,从而导致数据不一致
- 处理器提供了总线锁定和缓存锁定两种机制来保证复杂内存操作的原子性
- 总线锁定
- 当处理器要操作一个共享变量时,会在总线上会发出一个Lock信号,此时其它处理器就不能操作共享变量了
- 总线锁定在阻塞其他处理器获取该共享变量的操作请求时,也可能会导致大量阻塞,从而增加系统的性能开销
- 缓存锁定(后来出现)
- 当某个处理器对缓存中的共享变量进行了操作,就会通知其他处理器放弃存储或者重新读取该共享变量
- 目前最新的处理器都支持缓存锁定机制
- 总线锁定

优化CAS乐观锁
- 乐观锁在并发性能上要优于悲观锁
- 但在写大于读的操作场景下,CAS失败的可能性增大,如果循环CAS,会长时间占用CPU
- 例如上面的AtomicInteger#getAndIncrement
- JDK 1.8中,提供了新的原子类LongAdder
- LongAdder在高并发场景下会比AtomicInteger和AtomicLong的性能更好,代价是消耗更多的内存空间
- 核心思想:空间换时间
- 实现原理:降低操作共享变量的并发数
- LongAdder内部由一个base变量和一个cell[]数组组成
- 当只有一个写线程(没有竞争)
- LongAdder会直接使用base变量作为原子操作变量,通过CAS操作修改base变量
- 当有多个写线程(存在竞争)
- 除了占用base变量的一个写线程外,其他写线程的value值会分散到cell数组中
- 不同线程会命中到数组的不同槽中,各个线程只对自己槽中的value进行CAS操作
- value=base+∑ni=0Cell[i]value=base+∑i=0nCell[i]
- 当只有一个写线程(没有竞争)
- LongAdder在操作后的返回值只是一个近似准确的值,但最终返回的是一个准确的值
- LongAdder不适合实时性要求较高的场景
- LongAdder在高并发场景下会比AtomicInteger和AtomicLong的性能更好,代价是消耗更多的内存空间
性能对比
- 读大于写,读写锁ReentrantReadWriteLock、读写锁StampedLock、乐观锁LongAdder的性能最好
- 写大于读,乐观锁的性能最好,其他四种锁的性能差不多
- 读约等于写,两种读写锁和乐观锁的性能要优于synchronized和Lock
小结
- 乐观锁的常见使用场景:数据库更新
- 为每条数据定义一个版本号,在更新前获取版本号,在更新数据时,再判断版本号是否被更新过,如果没有才更新数据
- CAS乐观锁的使用比较受限,因为乐观锁只能保证单个变量操作的原子性
- CAS乐观锁在高并发写大于读的场景下
- 大部分线程的原子操作会失败,失败后的线程将不断重试CAS原子操作,导致大量线程长时间占用CPU资源
- JDK 1.8中,新增了原子类LongAdder,采用空间换时间的思路解决了这个问题,但实时性不高
- 本文作者: zhongmingmao
- 本文链接: http://zhongmingmao.me/2019/08/20/java-performance-cas/
- 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
Java性能 -- CAS乐观锁的更多相关文章
- Java:CAS(乐观锁)
本文讲解CAS机制,主要是因为最近准备面试题,发现这个问题在面试中出现的频率非常的高,因此把自己学习过程中的一些理解记录下来,希望能对大家也有帮助. 什么是悲观锁.乐观锁?在java语言里,总有一些名 ...
- CAS(乐观锁)以及ABA问题
https://blog.csdn.net/wwd0501/article/details/88663621独占锁是一种悲观锁,synchronized就是一种独占锁:它假设最坏的情况,并且只有在确保 ...
- Java并发:乐观锁
作者:汤圆 个人博客:javalover.cc 简介 悲观锁和乐观锁都属于比较抽象的概念: 我们可以用拟人的手法来想象一下: 悲观锁:像有些人,凡事都往坏的想,做最坏的打算:在java中就表现为,总是 ...
- Java并发问题--乐观锁与悲观锁以及乐观锁的一种实现方式-CAS
首先介绍一些乐观锁与悲观锁: 悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁.传统的关系型数据库里边就用到了很 ...
- JAVA多线程学习四 - CAS(乐观锁)
本文讲解CAS机制,主要是因为最近准备面试题,发现这个问题在面试中出现的频率非常的高,因此把自己学习过程中的一些理解记录下来,希望能对大家也有帮助. 什么是悲观锁.乐观锁?在java语言里,总有一些名 ...
- [数据库锁机制] 深入理解乐观锁、悲观锁以及CAS乐观锁的实现机制原理分析
前言: 在并发访问情况下,可能会出现脏读.不可重复读和幻读等读现象,为了应对这些问题,主流数据库都提供了锁机制,并引入了事务隔离级别的概念.数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务 ...
- Java中的乐观锁
1.前言 之前好几次看到有人在面经中提到了乐观锁与悲观锁,但是一本<Java Concurrency In Practice>快看完了都没有见到过这两种锁,今天终于在第15章发现了它们的踪 ...
- Java多线程:乐观锁、悲观锁、自旋锁
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁.传统的关系型数据 ...
- Java性能之synchronized锁的优化
synchronized / Lock 1.JDK 1.5之前,Java通过synchronized关键字来实现锁功能 synchronized是JVM实现的内置锁,锁的获取和释放都是由JVM隐式实现 ...
随机推荐
- 后端返回null,前端怎么处理?数据容错——不用过分相信外部数据
场景 我们在开发过程当中,总是会遇到因为数据原因,导致使用数组方法或者获取对象属性的时候报错. xxx is not fuction Cannot read property xxxx of unde ...
- u盘 安装 centOS 7
实际上, 对于服务器的安装, 最好是能够远程批量安装(可能有些难度, 不是专业运维) 镜像下载地址: http://59.80.44.49/isoredirect.centos.org/centos/ ...
- XCode保存问题
1. 确认下证书是不是开发证书,如果是发布证书就会出现这样的提示. 2. 证书失效了,去开发者中心重新生成一个. 3. 包标识符不与描述文件包含的包标识符不一致,按照它的提示换一下就好了,最好不要点 ...
- [20191013]oracle number类型存储转化脚本.txt
[20191013]oracle number类型存储转化脚本.txt --//测试看看是否可以利用bc obase=100的输出解决问题.另外以前脚本忘记考虑尾数的四舍五入问题.--//也许编程就是 ...
- python如何拼接时间戳到写入的文件名中
问题描述: 记录一下拼接文件名时间戳的过程,回顾下可能的问题所在,希望能帮到同样碰到这类问题的兄dei. 进行单元测试时,最后使用HTMLTestRunner生成的HTML分析报告,需要添加一个时间戳 ...
- Linux--NIS
一. 环境准备 操作系统:CentOS7.6 服务端安装如下软件: 软件名称 功能 ypserv NIS Server端的服务进程 rpcbind 提供RPC服务 客户端安装如下软件: 软件名称 功能 ...
- Mysql—配置文件my.ini或my.cnf的详解
[mysqld] log_bin = mysql-bin binlog_format = mixed expire_logs_days = # 超过7天的binlog删除 slow_query_log ...
- echarts使用简介
1. echarts是百度开源的一个前端图表库 2. 官网地址: https://www.echartsjs.com/zh/index.html 3. 使用介绍: 3.1. 下载echarts.js ...
- win10连接共享打印机
一.在运行中输入“\\共享打印机的主机ip”. 二.如果出现下面弹窗: 1.按Win键弹出开始菜单,直接在键盘上按zucelue,这个时候开始菜单里会检索到“编辑组策略”这个程序,按回车运行该程序.2 ...
- Pwnable-bof
Download : http://pwnable.kr/bin/bof Download : http://pwnable.kr/bin/bof.c 下载之后,先看看c源码 #include < ...