volatile无法保证i++原子性的解决方案
来源:互联网 发布:美国 制造业回归 知乎 编辑:程序博客网 时间:2024/05/22 10:37
一、阻塞算法与非阻塞算法
1、阻塞算法
以常见的同步实现方式synchronized
为例,同一时间段,同一个锁,只能有一个线程获得,其他未获取到的线程阻塞,直到拥有锁的线程释放锁。
下图演示了一个阻塞算法保证一个共享数据结构的行为:
2、非阻塞算法
线程A请求某种操作,如果系统无法响应;则通知A线程,A可先去执行其他操作;
下图演示了一个非阻塞算法保证一个共享数据结构的行为:
二、Volatile
变量存在的问题,
Volatile
变量写的内存语意:
当写一个Volatile
变量时,JMM会把线程对应的本地内存中的共享变量值刷新到主内存;
Volatile
变量读的内存语意:
当读一个Volatile变量时,JMM会把该线程对应的本地内存置为无效。重新主内存中读取共享变量;
还有一点需要注意:
对于任意单个volatile变量的读写具有原子性,但类似于
volatile++
这种复合操作不具有原子性;
public class SingleWriterCounter{ private volatile long count = 0; public void inc(){ this.count++; } public long count(){ return this.count; }}
例如上面这段代码,线程A和线程B分别执行100此inc
方法,最终count
的值可能为多少?
最小值2的解解释:
①A线程执行第99次
inc
方法,但是未写入主内存,此时主内存中count
的值任为0;
②此时B线程执行第1次inc
方法,从主内存中获取到的值为0
③A线程将执行第99次inc
方法的值写入主内存,此时主内存中的count
值为99;B线程将执行第1次inc
方法的结果写入主内存,此时主内存的count
值为1
④线程A执行第100次inc
方法,从主内存中获取到的值为1 ⑤线程B执行继续执行到第100次,并将100写入主内存;
⑥线程A将第100次inc
方法结果2写入主内容
最大值200的解释:①A线程执行100次并将结果100写入主内存;②B线程执行100次并将结果200写入主内存;
三、Volatile
问题的解决方案
解决方案一:阻塞算法
public class SynchronizedCounter{ long count = 0; public void inc(){ synchronized(this){ count++; } } public long count(){ synchronized(this){ return this.count; } }}
解决方案二:非阻塞算法
import java.util.concurrent.atomic.AtomicLong;public class AtomicLong{ private AtomicLong count = new AtomicLong(0); public void inc(){ boolean updated = false; while(!updated){ long prevCount = this.count.get(); updated = this.count.compareAndSet(prevCount, prevCount + 1); } } public long count(){ return this.count.get(); }}
现代CPU广泛支持一种对内存中的共享数据进行操作的一种特殊指令(CAS),该指令的语意如下:简单的来说,CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则返回V
CAS是一个原子操作,实现如下:
/** * 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 {@code true} if successful. False return indicates that * the actual value was not equal to the expected value. */ public final boolean compareAndSet(long expect, long update) { return unsafe.compareAndSwapLong(this, valueOffset, expect, update); }
非阻塞的解决方案的通俗解释如下:
小王去买奶茶,但是有很多人都在卖,此时小王有两种解决方案:
① 排队等待(阻塞算法)
② 过段时间再来买(非阻塞算法)
关于CAS的ABA问题,请参考:http://blog.hesey.net/2011/09/resolve-aba-by-atomicstampedreference.html
参考如下:
1、非阻塞算法 并发编网
2、《Java并发编程的艺术》
- volatile无法保证i++原子性的解决方案
- volatile不能保证原子性
- volatile 不能保证变量的原子性的操作
- 为何volatile不能保证原子性操作
- 为什么volatile不能保证原子性
- 为什么volatile不能保证原子性
- volatile不能保证程序执行的原子性以及只能一定程度上保证有序性
- volatile不能保证程序执行的原子性以及只能一定程度上保证有序性
- i++是原子操作吗?怎么保证其原子性
- java中volatile关键字的用法,它不能保证原子性操作
- volatile能保证long&double类型变量操作的原子性
- volatile 可以保证可见性,但不能保证原子性。某种意义上是线程不安全的
- 为什么volatile不能保证原子性而Atomic可以?
- 为什么volatile不能保证原子性而Atomic可以
- 为什么volatile不能保证原子性而Atomic可以?
- 为什么volatile不能保证原子性而Atomic可以
- 为什么volatile不能保证原子性而Atomic可以?
- 为什么volatile不能保证原子性而Atomic可以?
- Activity
- Java Map集合知识点整理(疯狂Java讲义读书笔记)
- android studio真机调试offline的问题
- Android横竖屏切换及其生命周期
- js日期初始化总结:new Date()参数设置
- volatile无法保证i++原子性的解决方案
- Oracle之分析函数应用- 连续值判断
- Spring Boot:(二)核心讲解
- 舵机
- [设计]代理模式
- 剑指offer---左旋转字符串
- spring-DI环境搭建
- 51nod 1052 最大m子段和 DP
- 基于matlab的图像处理-RGB色彩提取方法