volatile可以保证变量的可见性

当一个变量定义为volatile后,此变量对所有的线程具有可见性。这里的可见性是指当一个线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的。

每次使用volatile变量前都必须先从主内存刷新最新的值,这保证能看见其他线程对变量所做的修改后的值。每次修改volatile变量后都必须同步回主内存,这保证其他线程可以看到自己对变量所做的修改。正是这两条规则保证了volatile变量的可见性。

volatile要求线程每次从共享内存中读取变量,而不是私有内存中读取。

volatile可以保证有序性

volatile可以禁止指令重排序优化,重排序是指编译器和处理器为了优化程序性能而对指令序列进行排序的一种手段。但是重排序也需要遵守一定规则,重排序操作不会对存在数据依赖关系的操作进行重排序。比如:a=1;b=a; 这个指令序列,由于第二个操作依赖于第一个操作,所以在编译时和处理器运行时这两个操作不会被重排序。但是在多线程环境下,可能出现问题。如下示例:

    Map configOptions;
volatile boolean initialized = false; // 以下代码在线程A中执行
// 线程A完成配置信息后,initialized改为true
configOptions = new HashMap();
processConfigOptions(configOptions);
initialized = true; // 以下代码在线程B中执行
// 等待initialized为true,表示线程A已完成配置
while (!initialized) {
sleep();
}
// 线程A完成配置后,线程B可以开始doSomething();
doSomething();

initialized必须定义为volatile,否则可能出现线程A先赋值initialized为true,而后执行配置。

volatile保证了在赋值initialized之前,先执行完其前面的代码。

volatile 性能

  volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。

volatile在并发下运算是不安全的,不能保证原子性

如下示例,20个线程分别将变量race自加100次,运算结果race的值小于20000 。

public class VolatileTest {

    public static volatile int race;
public static void increase() {
race++;
} private static final int threads_count = 20; public static void main(String[] args) {
Thread[] threads = new Thread[threads_count]; for (int i=0; i<threads_count; i++) {
threads[i] = new Thread(
new Runnable() {
@Override
public void run() {
for (int i=0; i<100; i++) increase();
}
}
);
threads[i].start();
} System.out.println(race);
}
}

示例中,race++不是一个原子操作,其步骤分解如下:

1)从内存中取出race的值;

2)计算race的新值(加1);

3)将race的值写入内存中。

race是volatile修饰的,这保证了其可见性,即所有的线程在使用该变量时,都是从共享内存中读取。

但volatile不保证原子性,一个线程在进行第二步操作时,其它线程可以读取或修改race的值,这就出现了不同步的现象。

所谓原子性,是指一个操作或多个操作要么全部执行完成且执行过程不被中断,要么就不执行。例如,若race++是原子性的,某个线程在执行该操作时,其他线程不能干涉,必须等待其执行完毕。

java volatile的更多相关文章

  1. java volatile的一个验证反例(转)

    网上关于java volatile的资料已经不少了,但搜了好久也没看到谁用代码很好地验证过使不使用volatile的差异.最近自己写了个测试,意外的看到了两者的明显区别,为什么说意外呢,因为根据我的测 ...

  2. [Java并发编程(五)] Java volatile 的实现原理

    [Java并发编程(五)] Java volatile 的实现原理 简介 在多线程并发编程中 synchronized 和 volatile 都扮演着重要的角色,volatile 是轻量级的 sync ...

  3. [Java并发编程(四)] Java volatile 的理论实践

    [Java并发编程(四)] Java volatile 的理论实践 摘要 Java 语言中的 volatile 变量可以被看作是一种 "程度较轻的 synchronized":与 ...

  4. [Java并发编程(三)] Java volatile 关键字介绍

    [Java并发编程(三)] Java volatile 关键字介绍 摘要 Java volatile 关键字是用来标记 Java 变量,并表示变量 "存储于主内存中" .更准确的说 ...

  5. 13、Java并发性和多线程-Java Volatile关键字

    以下内容转自http://tutorials.jenkov.com/java-concurrency/volatile.html(使用谷歌翻译): Java volatile关键字用于将Java变量标 ...

  6. Java Volatile关键字(转)

    出处:  Java Volatile关键字 Java的volatile关键字用于标记一个变量“应当存储在主存”.更确切地说,每次读取volatile变量,都应该从主存读取,而不是从CPU缓存读取.每次 ...

  7. Java volatile 关键字底层实现原理解析

    本文转载自Java volatile 关键字底层实现原理解析 导语 在Java多线程并发编程中,volatile关键词扮演着重要角色,它是轻量级的synchronized,在多处理器开发中保证了共享变 ...

  8. Java volatile关键字详解

    Java volatile关键字详解 volatile是java中的一个关键字,用于修饰变量.被此关键修饰的变量可以禁止对此变量操作的指令进行重排,还有保持内存的可见性. 简言之它的作用就是: 禁止指 ...

  9. Java volatile的用法---转载

    我们知道,在Java中设置变量值的操作,除了long和double类型的变量外都是原子操作,也就是说,对于变量值的简单读写操作没有必要进行同步. 这在JVM 1.2之前,Java的内存模型实现总是从主 ...

  10. JAVA volatile 关键字

    一.volatile(易变的) Java 语言提供了一种稍弱的同步机制,即volatile修饰变量.用来确保将变量的更新操作通知到其他线程,保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新 ...

随机推荐

  1. shell脚本中if

    [[ $i =~ ^[0-9]+$ ]] && echo 1 的解释 =~ 表示的是匹配 && 是前一个命令为真 才执行后一个命令 [[ ]] 是if判断使用正则表达式 ...

  2. [数据结构]P1.2 队列

    * 注: 本文/本系列谢绝转载,如有转载,本人有权利追究相应责任. 2019年4月8日 Stan Zhang 2019年4月8日  格物致知,经世致用. 队列是一种先进先出FIFO的模型,常见操作有: ...

  3. VS 2017常用快捷键

    VS 2017常用快捷键 1.查找和替换 1)查找:使用组合键“Ctrl+F”: 2)替换:使用组合键“Ctrl+H”. (批量更改函数名的神器!) 2.复制/剪切/删除整行代码 1)如果你想复制一整 ...

  4. 搭建openstf平台的那些事

    最近老板建议秀下肌肉,搭建一个STF android 真机测试平台,记录一下坑. 1. stf 是node开发的,通过npm即可安静,依赖的数据库是rethinkdb, 如果搭配appium效果更佳, ...

  5. Shiro集成web环境[Springboot]-认证与授权

    Shiro集成web环境[Springboot]--认证与授权 在登录页面提交登陆数据后,发起请求也被ShiroFilter拦截,状态码为302 <form action="${pag ...

  6. vscode 快捷键

    ctrl+/   单行注释:// 若要多行注释://,先选中这些要注释的行,再按ctrl+/ shift+Alt+A 多行注释 撤销刚才的操作:Ctrl+Z 恢复刚才的操作:Ctrl+Shift+Z ...

  7. 纯CSS实现Div高度根据自适应宽度(百分百调整)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. day10_python_1124

    认知: 随着年龄阅历的变化而变化.01 去年内容回顾 *args **kwargs: 万能参数,动态参数 * 魔性用法: 函数的定义时,* ** 聚合. 函数的执行时,* ** 打散. 形参顺序: 位 ...

  9. or 的判断

    NeedCompact := NeedCompact or (AdoQ.ExecSQL > 0)

  10. vuex-getter

    store 的计算属性. getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算 const store = new Vuex.Store({ state: { t ...