Java原子类实现原理分析
在谈谈java中的volatile一文中,我们提到过并发包中的原子类可以解决类似num++这样的复合类操作的原子性问题,相比锁机制,使用原子类更精巧轻量,性能开销更小,本章就一起来分析下原子类的实现机理。
悲观的解决方案(阻塞同步)
我们知道,num++看似简单的一个操作,实际上是由1.读取 2.加一 3.写入 三步组成的,这是个复合类的操作(所以我们之前提到过的volatile是无法解决num++的原子性问题的),在并发环境下,如果不做任何同步处理,就会有线程安全问题。最直接的处理方式就是加锁。
synchronized(this){
num++;
}
使用独占锁机制来解决,是一种悲观的并发策略,抱着一副“总有刁民想害朕”的态势,每次操作数据的时候都认为别的线程会参与竞争修改,所以直接加锁。同一刻只能有一个线程持有锁,那其他线程就会阻塞。线程的挂起恢复会带来很大的性能开销,尽管jvm对于非竞争性的锁的获取和释放做了很多优化,但是一旦有多个线程竞争锁,频繁的阻塞唤醒,还是会有很大的性能开销的。所以,使用synchronized或其他重量级锁来处理显然不够合理。
乐观的解决方案(非阻塞同步)
乐观的解决方案,顾名思义,就是很大度乐观,每次操作数据的时候,都认为别的线程不会参与竞争修改,也不加锁。如果操作成功了那最好;如果失败了,比如中途确有别的线程进入并修改了数据(依赖于冲突检测),也不会阻塞,可以采取一些补偿机制,一般的策略就是反复重试。很显然,这种思想相比简单粗暴利用锁来保证同步要合理的多。
鉴于并发包中的原子类其实现机理都差不太多,本章我们就通过AtomicInteger这个原子类来进行分析。我们先来看看对于num++这样的操作AtomicInteger是如何保证其原子性的。
/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
我们来分析下incrementAndGet的逻辑:
1.先获取当前的value值
2.对value加一
3.第三步是关键步骤,调用compareAndSet方法来来进行原子更新操作,这个方法的语义是:
先检查当前value是否等于current,如果相等,则意味着value没被其他线程修改过,更新并返回true。如果不相等,compareAndSet则会返回false,然后循环继续尝试更新。
compareAndSet调用了Unsafe类的compareAndSwapInt方法
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
Unsafe的compareAndSwapInt是个native方法,也就是平台相关的。它是基于CPU的CAS指令来完成的。
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
CAS(Compare-and-Swap)
CAS算法是由硬件直接支持来保证原子性的,有三个操作数:内存位置V、旧的预期值A和新值B,当且仅当V符合预期值A时,CAS用新值B原子化地更新V的值,否则,它什么都不做。
CAS的ABA问题
当然CAS也并不完美,它存在"ABA"问题,假若一个变量初次读取是A,在compare阶段依然是A,但其实可能在此过程中,它先被改为B,再被改回A,而CAS是无法意识到这个问题的。CAS只关注了比较前后的值是否改变,而无法清楚在此过程中变量的变更明细,这就是所谓的ABA漏洞。
Java原子类实现原理分析的更多相关文章
- 原子类java.util.concurrent.atomic.*原理分析
原子类java.util.concurrent.atomic.*原理分析 在并发编程下,原子操作类的应用可以说是无处不在的.为解决线程安全的读写提供了很大的便利. 原子类保证原子的两个关键的点就是:可 ...
- 对Java原子类AtomicInteger实现原理的一点总结
java原子类不多,包路径位于:java.util.concurrent.atomic,大致有如下的类: java.util.concurrent.atomic.AtomicBoolean java. ...
- Java原子类AtomicInteger实现原理的一点总结
java原子类不多,包路径位于:java.util.concurrent.atomic,大致有如下的类: java.util.concurrent.atomic.AtomicBoolean java. ...
- JAVA常用数据结构及原理分析
JAVA常用数据结构及原理分析 http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balaba ...
- Java原子类中CAS的底层实现
Java原子类中CAS的底层实现 从Java到c++到汇编, 深入讲解cas的底层原理. 介绍原理前, 先来一个Demo 以AtomicBoolean类为例.先来一个调用cas的demo. 主线程在f ...
- (6)Java数据结构-- 转:JAVA常用数据结构及原理分析
JAVA常用数据结构及原理分析 http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balab ...
- 死磕 java原子类之终结篇(面试题)
概览 原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何线程上下文切换. 原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割 ...
- Java NIO使用及原理分析 (四)
在上一篇文章中介绍了关于缓冲区的一些细节内容,现在终于可以进入NIO中最有意思的部分非阻塞I/O.通常在进行同步I/O操作时,如果读取数据,代码会阻塞直至有 可供读取的数据.同样,写入调用将会阻塞直至 ...
- Java NIO使用及原理分析 (四)(转)
在上一篇文章中介绍了关于缓冲区的一些细节内容,现在终于可以进入NIO中最有意思的部分非阻塞I/O.通常在进行同步I/O操作时,如果读取数据,代码会阻塞直至有 可供读取的数据.同样,写入调用将会阻塞直至 ...
随机推荐
- JDK 升级问题小结
JDK8 发布很久了,它提供了许多吸引人的新特性,能够提高编程效率. 如果是新的项目,使用 JDK8 当然是最好的选择.但是,对于一些老的项目,升级到 JDK8 则存在一些兼容性问题,是否升级需要酌情 ...
- 如何把js的代码写的更加容易维护(一)--面向对象编程
总是头疼javascript的代码写起来不可维护,那么看看下面的代码: (function (w, $) { var app = { init: function () { var me = this ...
- BootStrap学习(2)_下拉菜单&按钮组
一.下拉菜单 1.基本下拉菜单 如需使用下列菜单,只需要在class .dropdown 内加上下拉菜单即可.下面的实例演示了基本的下拉菜单: <!DOCTYPE html> <ht ...
- 控制反转IOC与依赖注入DI - 理论篇
学无止境,精益求精 十年河东十年河西,莫欺少年穷 昨天是五一小长假归来上班的第一天,身体疲劳,毫无工作热情.于是就看看新闻,喝喝茶,荒废了一天 也就在昨天,康美同事张晶童鞋让我学习下IOC的理论及实现 ...
- NOIP常见模板集合
Preface 这篇博客记录的是我联赛前虽然只有两天了的打板子记录. 只求真的能给我起到些作用吧,一般按照难度排序. 而且从这篇博客开始我会用H3的标题代替H4 为了节约篇幅,以下的代码一般均以cla ...
- STM32 M3内核的位带操作原理及步骤
STM32 M3内核的位带操作原理及步骤 一.位带操作有什么用?什么是位带操作 位带操作的作用:可以实现对某一GPIO口寄存器(或SRAM内存中)的某一bit位直接写0或1,达到控制GPIO口输出(或 ...
- loj6062 pair
直接套用霍尔定理. 由于A有多个选择,考虑维护B是否合法. 首先B数组的顺序显然是没有用的,可以直接排序. 然后每个A就都变成了向一个后缀连边. 对于B,原本需要check每一个集合是否满足|u|&l ...
- Authorize的Forms认证
页面请求步骤: 1.登录地址: http://localhost:4441/SysLogin/AdminLogin 2.登陆成功地址:http://localhost:4441/Frame/MainF ...
- 牛客小白月赛6-E对弈-简单搜索
https://www.nowcoder.com/acm/contest/136/E 我搜索很差啊,看了学长代码,自己在下面手敲了一遍,感觉学长的极其精巧,把我繁琐的搜索步骤给简化了不少 其实本题想法 ...
- Visual Studio 2013版本安装
这周老师布置了关于Visual Studio 2013版本安装过程的概述,下面我就分享给大家看吧! 首先要下载安装文件,等待下载完成之后,虽然下载文件是ios格式,但我们可以用解压缩工具解压打开.解压 ...