原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11426473.html

关键字volatile的主要作用是使变量在多个线程间可见,但无法保证原子性,对于多个线程访问同一个实例变量需要加锁进行同步。

 package org.fool.java.concurrent.volatiletest;  

 import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class VolatileTest1 { private static volatile int count = 0; private static void addCount() {
for (int i = 0; i < 100; i++) {
count++;
} System.out.println(Thread.currentThread().getName() + " count = " + count);
} public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool(); for (int i = 0; i < 100; i++) {
executor.execute(new Runnable() {
@Override
public void run() {
VolatileTest1.addCount();
}
});
} executor.shutdown();
}
}

Note:

addCount()方法没有加synchronized

Console Output

预期结果应该是10000,尽管count被volatile修饰,保证了可见性,但是count++并不是一个原子性操作,它被拆分为load、use、assign三步,而这三步在多线程环境中,use和assgin是多次出现的,但这操作是非原子性的,也就是在read和load之后,如果主内存count变量发生修改之后,线程工作内存中的值由于已经加载,不会产生对应的变化,也就是私有内存和公有内存中的变量不同步,所以计算出来的值和预期不一样,就产生了线程安全的问题,所以需要用synchronized进行加锁同步

addCount()方法用synchronized进行加锁同步

Console Output

结果10000与预期一致

所以volatile只能保证可见性不能保证原子性,但用volatile修饰long和double可以保证其操作原子性

所以从Oracle Java Spec里面可以看到:

  • 对于64位的long和double,如果没有被volatile修饰,那么对其操作可以不是原子的。在操作的时候,可以分成两步,每次对32位操作。
  • 如果使用volatile修饰long和double,那么其读写都是原子操作
  • 对于64位的引用地址的读写,都是原子操作
  • 在实现JVM时,可以自由选择是否把读写long和double作为原子操作
  • 推荐JVM实现为原子操作

Reference

http://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.7

http://www.cnblogs.com/louiswong/p/5951895.html

http://ifeve.com/volatile/

http://www.infoq.com/cn/articles/java-memory-model-4/

Java中volatile如何保证long和double的原子性操作的更多相关文章

  1. java中volatile不能保证线程安全

    今天打了打代码研究了一下java的volatile关键字到底能不能保证线程安全,经过实践,volatile是不能保证线程安全的,它只是保证了数据的可见性,不会再缓存,每个线程都是从主存中读到的数据,而 ...

  2. Java中Volatile关键字详解

    一.基本概念 先补充一下概念:Java并发中的可见性与原子性 可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值, ...

  3. java中volatile

    volatile用来修饰变量.Java 语言中的 volatile 变量可以被看作是一种 "程度较轻的 synchronized":与 synchronized 块相比,volat ...

  4. java中volatile关键字的理解

    一.基本概念 Java 内存模型中的可见性.原子性和有序性.可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有 ...

  5. Java中Volatile关键字详解(转载)

    转载自:https://www.cnblogs.com/zhengbin/p/5654805.html 一.基本概念 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性是 ...

  6. Java中Volatile关键字详解 (转自郑州的文武)

    java中volatile关键字的含义:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html 一.基本概念 先补充一下概念:J ...

  7. 【转】java中volatile关键字的含义

    java中volatile关键字的含义   在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉. Java语言 ...

  8. 转:java中volatile关键字的含义

    转:java中volatile关键字的含义 在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉. Java语言 ...

  9. Java中Volatile的作用

    Java中Volatile的作用 看了几篇博客,发现没搞懂.可是简单来说,就是在我们的多线程开发中.我们用Volatile关键字来限定某个变量或者属性时,线程在每次使用变量的时候.都会读取变量改动后的 ...

随机推荐

  1. BiNGO的GO分析

    GO富集分析对老师们来说想必都不陌生,几乎在任何项目中都会出现.今天就给大家介绍一款简单易学又好用的富集分析小软件---BiNGO.它是Cytoscape软件中很出色的一个插件.它提供的结果中除了文本 ...

  2. element-ui中使用el-radio单选切换表格

    应用场景:点击单选,切换表格数据 代码: data里的数据:(这里的值是默认选中的   和label值是对应的) change事件操作切换,这里面添加@click事件是不生效的,注意...

  3. Delphi Win API 函数 [ ShellAPI ] ShellExecute 函数

    引用单元:uses ShellAPI; 函数原型:function ShellExecute(hWnd: HWND; Operation, FileName, Parameters,Directory ...

  4. web前端到底怎么学?

    互联网+的火爆,让互联网行业快速的扩张.越来越多的人想通过学习的途径进入这个行业,java开发.WEB前端开发.UI设计等专业受到大众追捧.小编这次主要介绍一下WEB前端开发,为想要学习web前端开发 ...

  5. [CF1161F]Zigzag Game

    通过这道模板题学了一种新的模型,记录一下. 稳定婚姻匹配 至于这道题,显然是一个二分图博弈的模型.考虑选择Bob,我们要找一组匹配使得任何情况下Bob都有匹配边能走.不失一般性假设Alice选择了in ...

  6. [CSP-S模拟测试]:联(小清新线段树)

    题目描述 由于出题人懒所以没有背景.一个无限长的$01$序列,初始全为$0$,每次选择一个区间$[l,r]$进行操作,有三种操作:$\bullet 1\ l\ r$将$[l,r]$中所有元素变成$1$ ...

  7. jQuery积累:serialize()、stringify()、toJSON()

    *)表单serialize()序列化,和serializeArray() ##)应用场景 当Ajax或者get请求发送表单中的某一个,或者某几个值到后台时,通过jQuery就能获取到这些值.然后作为A ...

  8. 父元素a标签的href默认行为以及子元素绑定的click事件的响应之间存在影响

    原文地址 背景 开发过程中遇到问题,简单写个demo 运行环境为Chrome 68 描述一下这个问题,当a标签内部存在嵌套时, 父元素a标签的href默认行为以及子元素绑定的click事件的响应之间存 ...

  9. python and 用法

    >>> 1 and [] and [1] [] >>> 1 and [2] and [1] [1] >>> 0 and [1] and [2] 0

  10. 结构体和typedef

    在C语言中,可以使用结构体(Struct)来存放一组不同类型的数据.结构体的定义形式为: struct 结构体名{    结构体所包含的变量或数组}; 结构体是一种集合,它里面包含了多个变量或数组,它 ...