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. C#实现基于ffmpeg加虹软的人脸识别

    关于人脸识别 目前的人脸识别已经相对成熟,有各种收费免费的商业方案和开源方案,其中OpenCV很早就支持了人脸识别,在我选择人脸 识别开发库时,也横向对比了三种库,包括在线识别的百度.开源的OpenC ...

  2. Archiva 2.2.3 安装运行的时候出现协议版本错误

    在 Archiva 安装成功后运行的时候出现协议版本错误: Caused by: javax.net.ssl.SSLException: Received fatal alert: protocol_ ...

  3. MogonDB安装及配置

    1.下载地址:https://www.mongodb.com/download-center/community?jmp=docs 选择下载MSI文件类型 2.双击安装 此处如勾选,则会影响安装速度, ...

  4. js获取当前时间:封装js的日期时间

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  5. Lua 语言变量

    Lua 变量 变量在使用前,必须在代码中进行声明,即创建该变量.编译程序执行代码之前编译器需要知道如何给语句变量开辟存储区,用于存储变量的值. Lua 变量有三种类型:全局变量.局部变量.表中的域. ...

  6. 微信支付---公众号支付和H5支付区别

    微信支付分为如下几种:(来源https://pay.weixin.qq.com/wiki/doc/api/index.html) 本文主要讲解公众号支付和H5支付,两者均属于线上支付比较常用的方式: ...

  7. boost range zhuan

    Officialhttp://67.223.234.84/boost_doc/libs/range/doc/utility_class.html#sub_range http://blog.sina. ...

  8. LimeSDR环境安装与测试

    虚拟机:ubuntu虚拟机建议4g内存,64g硬盘,usb3.0已开启 //否则编译过程耗尽内存 1 换阿里云源(加速)# deb cdrom:[Ubuntu 16.04 LTS _Xenial Xe ...

  9. exadata cellcli

    cellcli [port_number] [-n] [-m] [-xml] [-v | -vv | -vvv] [-x] [-e command] The following table lists ...

  10. flask 自动切换环境

    简介: 我就是个半吊子程序员.在单位写点程序,在家也写点程序. 单位是企业网,不能上互联网,家里也没办法连上企业网,没有VPN. 主武器是我的笔记本电脑.在单位有一台淘汰的linux服务器,家里有个N ...