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 关键字修饰函数 的作用是 告诉编译器该函数不会返回 , 让编译器能产生更好的代码 另外也能避免一些假警告信息,如未初始化的变量等
随机推荐
- idea内存不足或过大闪退
昨天在码云找了个开源后台项目https://gitee.com/shuzheng/zheng,各种修改后终于跑起来了, 运行没多久就提示内存不足,安装目录配置虚拟机最大可用内存为512M idea弹窗 ...
- Flutter移动电商实战 --(37)路由_Fluro引入和商品详细页建立
https://github.com/theyakka/fluro pages/details_page.dart新建页面 使用路由 先添加路由插件的引用 fluro: ^1.4.0 如果网络上下载不 ...
- linux中怎样会引起进程睡眠呢?
答: 使用信号量,wait队列,completion,调用schedule,用GFP_KERNEL指定的内存分配malloc,get,free,page等都会引起睡眠 思考: Q: 为什么会引起睡眠呢 ...
- SQL-W3School-高级:SQL LIKE 操作符
ylbtech-SQL-W3School-高级:SQL LIKE 操作符 1.返回顶部 1. LIKE 操作符用于在 WHERE 子句中搜索列中的指定模式. LIKE 操作符 LIKE 操作符用于在 ...
- 17. dashboard
17. dashboard dashboard的安装步骤: wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-bet ...
- 超详细MySQL安装及基本使用教程
一.下载MySQL 首先,去数据库的官网http://www.mysql.com下载MySQL. 点击进入后的首页如下: 然后点击downloads,community,选择MySQL Commun ...
- C#与C++数据类型比较及结构体转换(搜集整理二)
原文网址:http://www.blogjava.net/heting/archive/2010/03/20/315998.html C++ C# ========================== ...
- Qt编写安防视频监控系统2-视频播放
一.前言 视频播放功能是核心功能之一,为了统一管理接口,统一封装成一个控件,对外提供seturl open close方法即可,不用去管内部的具体处理,这样就可以提供多种接口来实现统一的管理,比如vl ...
- PAT 甲级 1016 Phone Bills (25 分) (结构体排序,模拟题,巧妙算时间,坑点太多,debug了好久)
1016 Phone Bills (25 分) A long-distance telephone company charges its customers by the following r ...
- windows10 企业版 安装应用商店
安装windows10企业版后,提示 没有nvdia control panel 在其他位置下载均不成功 必须在win10自带的应用商店中安装,但win10企业版没有应用商店, 使用下方的网盘安装应用 ...