volatile 关键字(修饰变量)
volatile 关键字(修饰变量)
1. 含义
是一种比 sychronized
关键字更轻量级的同步机制,访问 volitile
变量时,不会执行加锁操作。
2. 作用
volatile 是一个类型修饰符(type specifier)。volatile 的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
- 保证可见性
- 禁止指令重排序优化
指令重排序优化:普通的变量仅仅会保证在该方法的执行过程中所有依赖赋值结果的地方都能获取到正确的结果,而不能保证变量赋值操作的顺序和程序代码中的执行顺序一致
3. 如何保证可见性
新值能立即同步到主内存,以及每次使用前立即从主内存刷新。
volatile 修饰的变量,是直接拿的主内存的值,就是说这个值永远是最新的,对其他线程是可见的。
而访问非
volatile
变量时,每个线程都会从系统内存(主内存)拷贝变量到工作内存中,然后修改工作内存中的变量值,操控的变量可能不同。
4. 如何禁止指令重排序优化
volatile 通过设置 Java 内存屏障禁止重排序优化。
java 内存屏障
内存屏障也称为内存栅栏或栅栏指令,是一种屏障指令,它使CPU或编译器对屏障指令之前和之后发出的内存操作执行一个排序约束。 这通常意味着在屏障之前发布的操作被保证在屏障之后发布的操作之前执行。
java 的内存屏障通常所谓的四种即
LoadLoad
,StoreStore
,LoadStore
,StoreLoad
实际上也是上述两种的组合,完成一系列的屏障和数据同步功能。(
Load
指令(也就是从内存读取),Store指令
(也就是写入内存)。)
LoadLoad 屏障:对于这样的语句
Load1; LoadLoad; Load2
,在 Load2 及后续读取操作要读取的数据被访问前,保证Load1 要读取的数据被读取完毕。StoreStore 屏障:对于这样的语句
Store1; StoreStore; Store2
,在 Store2 及后续写入操作执行前,保证 Store1 的写入操作对其它处理器可见。LoadStore 屏障:对于这样的语句
Load1; LoadStore; Store2
,在 Store2 及后续写入操作被刷出前,保证 Load1 要读取的数据被读取完毕。StoreLoad 屏障:对于这样的语句
Store1; StoreLoad; Load2
,在 Load2 及后续所有读取操作执行前,保证 Store1 的写入对所有处理器可见。它的开销是四种屏障中最大的。在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能
volatile 做了什么
在一个变量被 volatile 修饰后,JVM 会为我们做两件事:
在每个 volatile 写操作前插入 StoreStore 屏障,在写操作后插入 StoreLoad 屏障。(
StoreStore-写-StoreLoad
)在每个 volatile 读操作前插入 LoadLoad 屏障,在读操作后插入LoadStore屏障。(
LoadLoad-读-LoadStore
)
5. volatile 是不安全的
虽然 volatile 可见性保证了对 volatile 变量所有的写操作都能立刻反应到其他线程之中(即 volatile 变量在各个线程中都是一致的),但是 Java 里面的运算并非原子操作。只有是原子操作的 volatile 变量才是线程安全的,比如我们很常见的 变量++ 自增操作,在这个过程中,自增包括取数,加一,保存三个过程的操作,所以自增并不是原子性操作,使用 volatile 修饰的变量自增操作仍然是不安全的。
举个例子:
public class MyVolitile {
private static volatile int count = 0;
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
count++;
}
}
}).start();
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(count);
}
}
结果每次都不一样,不一定等于 200。
6. volatile 不适用场景
由于 volatile 变量只能保证可见性,在不符合以下两条规则的运算场景中,我们仍然要通过加锁(使用 synchronized 或 java.util.concurrent 中的原子类)来保证原子性。
- 运算结果并不依赖变量的当前值,或者能够确保只有单一的线程修改变量的值
- 变量不需要与其他的状态变量共同参与不变约束
volatile 关键字(修饰变量)的更多相关文章
- Java学习笔记18---final关键字修饰变量、方法及类
英语里final这个单词大家都知道是"最终的"意思,其实还有一个意思是"不可更改的".在Java里,final关键字作"不可更改的"来解释更 ...
- Java中final关键字修饰变量、方法、类的含义是什么
Java中的关键字final修饰变量.方法.类分别表示什么含义? 先看一个简单的介绍 修饰对象 解释说明 备注 类 无子类,不可以被继承,更不可能被重写. final类中的方法默认是final的 方法 ...
- 使用 volatile 关键字保证变量可见性和禁止指令重排序
volatile 概述 volatile 是 Java 提供的一种轻量级的同步机制.相比于传统的 synchronize,虽然 volatile 能实现的同步性要差一些,但开销更低,因为它不会引起频繁 ...
- java的final关键字——修饰变量
final修饰的变量不可变,指的是引用不可变,(除基本类型)而不是内容. final修饰的成员变量必须被初始化
- Java并发编程:JMM和volatile关键字
转载请标明出处: http://blog.csdn.net/forezp/article/details/77580491 本文出自方志朋的博客 Java内存模型 随着计算机的CPU的飞速发展,CPU ...
- 【JUC系列第一篇】-Volatile关键字及内存可见性
作者:毕来生 微信:878799579 什么是JUC? JUC全称 java.util.concurrent 是在并发编程中很常用的实用工具类 2.Volatile关键字 1.如果一个变量被volat ...
- 架构师养成记--4.volatile关键字
volatile修饰的变量可在多个线程间可见. 如下代码,在子线程运行期间主线程修改属性值并不对子线程产生影响,原因是子线程有自己独立的内存空间,其中有主内存中的变量副本. public class ...
- volatile关键字及编译器指令乱序总结
本文简单介绍volatile关键字的使用,进而引出编译期间内存乱序的问题,并介绍了有效防止编译器内存乱序所带来的问题的解决方法,文中简单提了下CPU指令乱序的现象,但并没有深入讨论. 以下是我搭建的博 ...
- Java单例模式和volatile关键字
单例模式是最简单的设计模式,实现也非常"简单".一直以为我写没有问题,直到被 Coverity 打脸. 1. 暴露问题 前段时间,有段代码被 Coverity 警告了,简化一下代码 ...
- [其他]volatile 关键字
用 volatile 关键字修饰函数 的作用是 告诉编译器该函数不会返回 , 让编译器能产生更好的代码 另外也能避免一些假警告信息,如未初始化的变量等
随机推荐
- 使用vagrant一键部署本地php开发环境(一)
一:我们为什么需要用这玩意 我们在开发中经常会面临的问题:环境不一致,有人用Mac有人用Windos还有几个用linux的,而我们的服务器都是linux. 在我本地是可以的啊,我测了都,没有问题 ...
- JAVA将两个byte数组合并为一个
/** * 将两个byte数组合并为一个 * @param data1 要合并的数组1 * @param data2 要合并的数组2 * @return 合并后的新数组 */ public stati ...
- Android-Handler消息机制实现原理)(转)
Android-Handler消息机制实现原理 一.消息机制流程简介 在应用启动的时候,会执行程序的入口函数main(),main()里面会创建一个Looper对象,然后通过这个Looper对象开 ...
- produceTestDate
set serveroutput on --使用基本变量类型 declare --定义基本变量:类型 --基本数据类型 pnumber , ); pname ); pdate date; begin ...
- smart_pointer example
#pragma oncetemplate<typename T>class smart_pointer{private: T* m_pRawPointer;public: smart_po ...
- 阶段5 3.微服务项目【学成在线】_day05 消息中间件RabbitMQ_7.RabbitMQ研究-工作模式-工作队列模式
RabbitMQ有以下几种工作模式 : 1.Work queues 2.Publish/Subscribe 3.Routing 4.Topics 5.Header 6.RPC 1.Work queue ...
- 一百三十七:CMS系统之发布帖子前台布局
把前面配置好的ueditor的文件复制到static下 把ueditor蓝图导入,注册 初始化ueditor //初始化ueditor$(function () { var ue = UE.getEd ...
- Goland 激活码
实测有效,分享下 Goland
- 运行React Native项目出现白屏,无法运行
运行React Native出现白屏,无法运行,查看终端报错如下: 原因: 代码中有语法错误,导致运行失败. 其实到这里可以去Xcode查看控制台打印,会提示哪个文件出现错误的. 解决办法: 找到报错 ...
- postman使用当前时间戳
//设置当前时间戳postman.setGlobalVariable(“time”,Math.round(new Date().getTime()));time = postman.getGlobal ...