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. TexStudio + TexLive 修改字体大小

    \tiny \scriptsize \footnotesize \small \normalsize \large \Large \LARGE \huge \Huge 将上述命令放在文本之前即可

  2. 服务列表中找不到mysql

    服务列表中找不到mysql - 解决办法 1.在开始处输入cmd,找到cmd选择以管理员身份运行(必须以管理员运行,直接win+r打开无效) 2.进入到MySQL安装目录的bin目录 3.执行mysq ...

  3. nova相关操作的Request_Id的获取

    在分析nova的众多log文件时,如nova-api,nova-scheduler,nova-compute等,其中的request id是串联起整个flow的关键词. 而通过nova instanc ...

  4. erlang 笔记(06/03/02)

    1 .同时打开的端口数量限制(Open ports) erlang:system_info(port_limit)查询 可以通过环境变量ERL_MAX_PORTS修改,或者配置erlang启动参数(标 ...

  5. 记录一个下最近用tensorflow的几个坑

    1, softmax_cross_entropy_with_logits 的中的logits=x*w+b,其中w应该是[nfeats,nclass],b是[nclass]是对输出的每个类上logits ...

  6. ProtoBuf3.3 安装记录

    翻了很多教程,下载了 PB 的源码在自己的 mac 上编译及安装,记录下新的 1. 首先是下载源码了 https://github.com/google/protobuf/releases 虽然是 g ...

  7. REACT Missing “key” prop for element

    https://stackoverflow.com/questions/48266018/missing-key-prop-for-element-reactjs-and-typescript Whe ...

  8. nio 序列化

    1.序列化 public class SerializeUtils<T extends Serializable> { public byte[] serialize(T t) { byt ...

  9. 表单验证,添加动态class

  10. Javascript获取图片原始宽度和高度的方法详解

    前言 网上关于利用Javascript获取图片原始宽度和高度的方法有很多,本文将再次给大家谈谈这个问题,或许会对一些人能有所帮助. 方法详解 页面中的img元素,想要获取它的原始尺寸,以宽度为例,可能 ...