一、简述:
  关键字Volatile是JAVA虚拟机提供的最轻量级的同步机制,但是它并不容易完全被正确、完整的理解,以致于许多程序员在遇到需要处理多线程数据竞争的时候一律使用synchronized来进行同步,了解volatile变量的语义对后面了解多线程操作的其他特性很有意义。

二、应用:
  当一个变量被定义为volatile之后,它将具备两种特性:
  1. 保证此变量对所有线程的可见性:
    这里的可见性是指当一个线程修改了变量的值,新值对于其他线程来说是可以立即得知的,而普通变量不能做到这一点,普通变量的值在线程间传递需要通过主内存来完成。
    volatile变量在各个线程中是一致的,但基于volatile变量的运算在并发下却不一定是安全的,参见如下案例:

public class Volatile {
public static volatile int count = 0; public static void increaseCount() {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
};
count++;
} public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
new Thread(new Runnable() {
@Override
public void run() {
increaseCount();
}
}).start();
}
System.out.println("count值: " + count);
}
}

  预想的返回值应该是1000,但实际的返回结果值却是小于1000的值,原因在于:

  利用javap发编译后得到代码清单,对应的increaseCount()对应的字节码指令如下:

public static void increaseCount();
Code :
Stack=2, Locals=0, Args_size=0
0: getstatic
3: iconst_1
4: iadd
5: putstatic
8: return

  当getstatic指令把count的值取到操作栈顶是,volatile关键字保证了count在此时是正确的,但是在执行iconst_1、iadd这些指令时,其他线程可能已经把count的值加大了,而在操作栈顶的数据就变成了过期的数据,所以putstatic执行后就可能把较小的count值同步回主内存中了。

  所以,由于volatile变量只能保证可见性,在不符合以下两条规则的运算场景中,仍需要通过加锁来保证原子性:
    1)运算结果并不依赖变量的当前值,或者能够确保只有单一的线程修改变量值;
    2)变量不需要与其他的状态变量共同参与不变约束。

  2. 禁止指令重排序优化
    普通的变量仅仅会保证在该方法的执行过程中所有依赖赋值结果的地方都能获取到正确的结果,而不能保证变量赋值操作的顺序与程序代码中的执行顺序一致,如下场景:
      boolean flag = false;

      线程A:
      doSomeThing();
      flag = true;

      线程B:
      while(!flag){
        doSomeThingElse();
      }

      A.doSomeThing();//调用A线程的方法

    如果定义flag变量时如果没有使用volatile修饰,就有可能由于指令重排序的优化,导致位于线程A中最后一句"flag = true"被提前执行,这样在线程B中调用的A的方法就有可能出现错误,使用volatile可以避免此现象的发生。

三、总结
  volatile的同步性能机制要优于synchronized,但由于虚拟机对锁实行的许多消除和优化,实际上我们很难量化的认为volatile会比synchronized快多少,但volatile跟自己相比而言:volatile变量读操作的性能消耗与普通变量几乎没什么差别,但是写操作则可能慢一些,因为他需要在本地代码中插入许多内存屏障来保证处理器不发生乱序执行。

JAVA关键字Volatile的特性的更多相关文章

  1. Java 关键字volatile的解释

    volatile 关键字特征: 1.可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的.可以禁止线程的工作内存对volatile修饰的变量进行缓存,并将修改的变量立即写入主存. 2. ...

  2. Java关键字-volatile

    关键字volatile可以说是Java虚拟机提供的最轻量级的同步机制. 一旦某个共享变量(类的成员变量.类的静态成员变量)被volatile修饰之后,那么就具备了两层语义: 1.保证了不同线程对这个变 ...

  3. Java内存模型及Java关键字 volatile的作用和使用说明

    先来看看这个关键字是什么意思:volatile  [ˈvɒlətaɪl] adj. 易变的,不稳定的; 从翻译上来看,volatile表示这个关键字是极易发生改变的.volatile是java语言中, ...

  4. 关于 Java 关键字 volatile 的总结

    1 什么是 volatile volatile 是 Java 的一个关键字,它提供了一种轻量级的同步机制.相比于重量级锁 synchronized,volatile 更为轻量级,因为它不会引起线程上下 ...

  5. java 关键字volatile

    一.Java内存模型 想要理解volatile为什么能确保可见性,就要先理解Java中的内存模型是什么样的. Java内存模型规定了所有的变量都存储在主内存中.每条线程中还有自己的工作内存,线程的工作 ...

  6. java关键字volatile用法详解

    volatile关键字想必大家都不陌生,在java 5之前有着挺大的争议,在java 5之后才逐渐被大家接受,同时作为java的关键字之一,其作用自然是不可小觑的,要知道它是java.util.con ...

  7. 深入汇编指令理解Java关键字volatile

    volatile是什么 volatile关键字是Java提供的一种轻量级同步机制.它能够保证可见性和有序性,但是不能保证原子性 可见性 对于volatile的可见性,先看看这段代码的执行 flag默认 ...

  8. java关键字volatile内存语义详细分析

    volatile变量自身具有下列特性. 1.可见性.对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写 入. · 2.原子性:对任意单个volatile变量的读/ ...

  9. Java 关键字volatile 与 synchronized 作用与区别

     1,volatile 它所修饰的变量不保留拷贝,直接访问主内存中的.    在Java内存模型中,有main memory,每个线程也有自己的memory (例如寄存器).为了性能,一个线程会在自己 ...

随机推荐

  1. SpringBoot(一)走进Springboot的世界

    什么是spring boot Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员 ...

  2. codeforces 767A Snacktower(模拟)

    A. Snacktower time limit per test:2 seconds memory limit per test:256 megabytes input:standard input ...

  3. [bzoj2638] 黑白染色

    比较蛋疼的是我们可以先染个底色,再在底色上染别的东西. 由ccz大爷的题解可得..将目标状态里相同颜色的联通块缩点后,枚举起点,生成树里的最大节点深度就是需要的次数了, 如果最大深度是白色的话记得-1 ...

  4. 2017ecjtu-summer training #5 UVA10382

    题意 问最少可用几个圆覆盖矩形区域. 解析 将圆形转换成矩形有效区域,直径小于等于宽度的圆不考虑,从而转化成区间覆盖问题,然后贪心出最少圆. 贪心思想 每次选择出区域左界比上次选出的区域右界小的且区域 ...

  5. 启动tomcat时,一直卡在Deploying web application directory这块的解决方案

    本来今天正常往服务器上扔一个tomcat 部署一个项目的, 最后再启动tomcat 的时候 发现项目一直都访问不了,看了一下日志: [root@iz8vbdzx7y7owm488t4d89z bin] ...

  6. 一个简洁的PHP可逆加密函数(分享)

    http://www.jb51.net/article/38018.htm 本篇文章是对一个简洁的PHP可逆加密函数进行了详细的分析介绍,需要的朋友参考下   很多时候我们需要对数据进行加密解密,比如 ...

  7. C#中的基元类型、值类型和引用类型

    C# 中的基元类型.值类型和引用类型 1. 基元类型(Primitive Type) 编译器直接支持的类型称为基元类型.基元类型可以直接映射到 FCL 中存在的类型.例如,int a = 10 中的 ...

  8. nodejs+websocket实时聊天系统

    介绍下websocket: webSocket协议本质上是一个基于tcp的协议; 建立一个websocket连接,大体的过程: 1.客户端浏览器首先向服务器发起一个http请求,这个请求和平常的请求有 ...

  9. sql语句添加删除外键及其约束

    --删除外键 ALTER TABLE t_base_role_module DROP CONSTRAINT fk_t_base_role_module_t_base_defined_url; --增加 ...

  10. Python3之数据类型

    1.基本数据类型数字类型整型 int浮点型 float布尔型 bool: True==1.False==0复数类型 complex算术运算符 + - * / // % **赋值运算符 += -= *= ...