关于关键字volatile可以说是Java虚拟机提供的轻量级的同步机制,但是它并不容易完全被正常、完整地理解,以至于许多程序员都不习惯去使用它,遇到需要处理多线程数据竞争问题的时候一律使用Synchronized来进行同步。了解volatile变量的语义对了解多线程操作的其他特性很有意义。

当一个变量定义为volatile后,它将具备两种特性,第一是保证此变量对所有线程的可见性,这里的”可见性“是指当一条线程修改了这个变量的值,新值对于其它线程来说是可以立即得知的。而普通变量是做不到这一点,普通变量的值在线程间传递均需要通过主内存来完成,例如,线程A修改一个普通变量的值,然后向主内存进行回写,另外一条线程B在线程A回完成了之后再从主内存进行读取操作,新变量值才会对线程B可见。

特性一:可见性

介绍到这里可能很多朋友会说,并发线程吗我把变量声明称volatile就可以了嘛,哪里有那么复杂,事实并非如此,看段代码:

import java.util.concurrent.*;

/**
* by lv xiao long
*/
public class App {
public static volatile int count; public static void increase() {
++count;
} private static final int THREADS_COUNT = 10; private static CountDownLatch countDownLatch=new CountDownLatch(10); public static void main(String[] args) {
// 线程池
ExecutorService exec = Executors.newCachedThreadPool();
// 启动10条线程,每条线程连续自增1000次。最后count等于10*1000对吗?
for (int index = 0; index < THREADS_COUNT; index++) {
Runnable run = new Runnable() {
public void run() {
for (int i=0;i<1000;i++){
increase();
}
countDownLatch.countDown();
}
};
exec.execute(run);
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
//等待所有线程结束
exec.shutdown();
System.out.print(count);
}
}

  最后结果你会看到不是10*1000,按道理来说在线程中使用volatile变量,每次使用之前都要先刷新,执行引擎看不到不一致情况 ,因此不存在一致性问题,但是在java里面运算并非原子操作,导致volatitle变量的运算在并发下一样是不安全的。

由于volatitle变量只能保证可见性,在不符合以下两条规则的运算场景中,我们仍然要通过加锁(使用synchronized或java.util.conrueent中的原子类)来保证原子性。

规则1:运行结果并不依赖变量当前值,或者能够确保只有单一线程修改变量的值。

规则2:变量不需要与其他的状态变量共同参与不变约束。

例如下面场景:

volatile boolean off;

public void shutdown(){
off=true;
} public void doWork(){ while(!off){
//do stuff
}
}

特性二:禁止指令重排序优化

普通的变更仅仅会保证在该方法的执行过程中所有依赖赋值结果的地方都能获取到正确的结果,而不能保证变量赋值操作的顺序与程序代码中的执行顺序一致。因为在一个线程的方法执行过程中无法感知到这点,这也就是java 内存模型中描述的所谓的”线程内表现为串行的语义“

Map configOptions;

char[] configText;

//此变量必须定义为volatile
volatile boolean initialized = false; //假设以下代码在线程A中执行
configOptions=new HashMap(); configText=readConfigFile(fileName); processConfigOptions(configText,configOptions); initialized =true; //假设以下代码在线程B中执行
while(!initialized ){ sleep(); }
doSomethingWithConfig();

上面代码定义initialized 变量时没有使用volatile修饰,就可能会由于指令重排序优化,导致位于线程A中最后一句代码”initialized =true“提前被执行,得不到最终你想要的结果。

如果在面试过程中,遇到有关volatile相关的话题,可以简明扼要的说明volatile两种特性,以及适用的一些场景,个人觉得一般都能通过。

java volatitle介绍与使用的更多相关文章

  1. Android下HelloWorld项目的R.java文件介绍

    R.java文件介绍 HelloWorld工程中的R.java文件 package com.android.hellworld; public final class R {     public s ...

  2. 深入Java虚拟机读书笔记第一章Java体系结构介绍

    第1章 Java体系结构介绍 Java技术核心:Java虚拟机 Java:安全(先天防bug的设计.内存).健壮.平台无关.网络无关(底层结构上,对象序列化和RMI为分布式系统中各个部分共享对象提供了 ...

  3. java集合介绍(List,Set,Map)

    前言 介绍java的常用集合+各个集合使用用例 欢迎转载,请注明作者和出处哦☺ 参考: 1,<Java核心编程技术(第二版)> 2, http://www.cnblogs.com/Litt ...

  4. Java学习介绍

    Java版本介绍 JavaME:微型版,用于开发小型设备.智能卡.移动终端应用(使用率较低) JavaSE:标准版,用于创建桌面应用(企业用JavaSE创建桌面应用较少) JavaEE:企业版,用于创 ...

  5. 流行的9个Java框架介绍: 优点、缺点等等

    流行的9个Java框架介绍: 优点.缺点等等 在 2018年,Java仍然是世界上最流行的编程语言.它拥有一个巨大的生态系统,在全世界有超过900万Java开发人员.虽然Java不是最直接的语言,但是 ...

  6. Java监控工具介绍,VisualVm ,JProfiler,Perfino,Yourkit,Perf4J,JProbe,Java微基准测试【转】

    Java监控工具介绍,VisualVm ,JProfiler,Perfino,Yourkit,Perf4J,JProbe,Java微基准测试[转] 本文是本人前一段时间做一个简单Java监控工具调研总 ...

  7. java JNI介绍

    java JNI介绍 目录 java JNI介绍 1. Java调用C++代码 2.C++代码调用java代码 JNI是Java Native Interface的全称. oracle文档中是这样描述 ...

  8. Java秘诀!Java逻辑运算符介绍

    运算符丰富是 Java 语言的主要特点之一,它提供的运算符数量之多,在高级语言中是少见的. Java 语言中的运算符除了具有优先级之外,还有结合性的特点.当一个表达式中出现多种运算符时,执行的先后顺序 ...

  9. Java秘诀!Java赋值运算符介绍

    运算符丰富是 Java 语言的主要特点之一,它提供的运算符数量之多,在高级语言中是少见的. Java 语言中的运算符除了具有优先级之外,还有结合性的特点.当一个表达式中出现多种运算符时,执行的先后顺序 ...

随机推荐

  1. java封装FFmpeg命令,支持原生ffmpeg全部命令,实现FFmpeg多进程处理与多线程输出控制(开启、关闭、查询),rtsp/rtmp推流、拉流

    前言: 之前已经对FFmpeg命令进行了封装http://blog.csdn.net/eguid_1/article/details/51787646,但是当时没有考虑到扩展性,所以总体设计不是太好, ...

  2. form表单在前台转json对象

    会发生序列化乱码问题,待解决. //根据表单id将其内空间,名称,值转为json var fireTraceEquipment =queryParamByFormId('form1'); functi ...

  3. 初识webpack——webpack四个基础概念

    前面的话 webpack是当下最热门的前端资源模块化管理和打包工具.它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源.当webpack处理应用程序时,它会递归地构建一个依赖关系图表 ...

  4. PO/VO/POJO/BO/VO图解

  5. js移动端/H5同时选择多张图片上传并使用canvas压缩图片

    最近在做一个H5的项目,里边涉及到拍照上传图片的功能以及识别图片的功能,这里对识别图片的功能不做赘述,不属本文范畴.我在做完并上线项目后,同事跟我提了一个要求是可不可以同时选择多张图片上传,我做的时候 ...

  6. SpringMVC学习资料

    一.SpringMVC 1.helloworld 1.导包 <dependency> <groupId>org.springframework</groupId> ...

  7. 网页中区分IE各版本

    CSS Hack 直接在CSS文件中写CSS Hack是非常直观的区分方法.区分不同IE版本的hack代码为 #content{ background:red; /* 所有浏览器 */ backgro ...

  8. flask简单web应用

    推荐一个学习python的网站,个人觉得在这里面收获挺大的,希望对后来学习flask的小伙伴们有帮助.http://www.pythondoc.com/ 用flask框架实现第一个web应用 首先需要 ...

  9. 记一次使用搬瓦工VPS的经历

    自己因为有需求上Google,以前是通过修改hosts的方法实现访问Google,但是最近不知道为什么改hosts后还是无法访问Google,于是决定搭建VPS来实现科学上网,看了一下价格,作为穷逼学 ...

  10. memcache常用命令

    一.memcached的基本命令(安装.卸载.启动.配置相关): -p 监听的端口 -l  连接的IP地址, 默认是本机   -d start 启动memcached服务 -d restart 重起m ...