java volatitle介绍与使用
关于关键字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介绍与使用的更多相关文章
- Android下HelloWorld项目的R.java文件介绍
R.java文件介绍 HelloWorld工程中的R.java文件 package com.android.hellworld; public final class R { public s ...
- 深入Java虚拟机读书笔记第一章Java体系结构介绍
第1章 Java体系结构介绍 Java技术核心:Java虚拟机 Java:安全(先天防bug的设计.内存).健壮.平台无关.网络无关(底层结构上,对象序列化和RMI为分布式系统中各个部分共享对象提供了 ...
- java集合介绍(List,Set,Map)
前言 介绍java的常用集合+各个集合使用用例 欢迎转载,请注明作者和出处哦☺ 参考: 1,<Java核心编程技术(第二版)> 2, http://www.cnblogs.com/Litt ...
- Java学习介绍
Java版本介绍 JavaME:微型版,用于开发小型设备.智能卡.移动终端应用(使用率较低) JavaSE:标准版,用于创建桌面应用(企业用JavaSE创建桌面应用较少) JavaEE:企业版,用于创 ...
- 流行的9个Java框架介绍: 优点、缺点等等
流行的9个Java框架介绍: 优点.缺点等等 在 2018年,Java仍然是世界上最流行的编程语言.它拥有一个巨大的生态系统,在全世界有超过900万Java开发人员.虽然Java不是最直接的语言,但是 ...
- Java监控工具介绍,VisualVm ,JProfiler,Perfino,Yourkit,Perf4J,JProbe,Java微基准测试【转】
Java监控工具介绍,VisualVm ,JProfiler,Perfino,Yourkit,Perf4J,JProbe,Java微基准测试[转] 本文是本人前一段时间做一个简单Java监控工具调研总 ...
- java JNI介绍
java JNI介绍 目录 java JNI介绍 1. Java调用C++代码 2.C++代码调用java代码 JNI是Java Native Interface的全称. oracle文档中是这样描述 ...
- Java秘诀!Java逻辑运算符介绍
运算符丰富是 Java 语言的主要特点之一,它提供的运算符数量之多,在高级语言中是少见的. Java 语言中的运算符除了具有优先级之外,还有结合性的特点.当一个表达式中出现多种运算符时,执行的先后顺序 ...
- Java秘诀!Java赋值运算符介绍
运算符丰富是 Java 语言的主要特点之一,它提供的运算符数量之多,在高级语言中是少见的. Java 语言中的运算符除了具有优先级之外,还有结合性的特点.当一个表达式中出现多种运算符时,执行的先后顺序 ...
随机推荐
- 【Android】又一个Gank客户端来啦
介绍 Gank平台的移动端又来了,非常感谢Gank平台开放接口,让我们这些小白有机会练手.学习. 本项目在架构方面有稍微花点心思,虽然还是最简单的MVC模式,但基本参考MVP的思想,Activity只 ...
- 小K的H5之旅-实战篇(一)
一.前言 本K在经过两个星期的html和css学习之后,第一次去尝试完成一个网站主页的制作.在四天之后,本K也终于完成了杰瑞教育主页的html和css部分,至于部分涉及js的部分,因为本K还没有学习过 ...
- Java中设计模式之装饰者模式-3
装饰者模式: 动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更加有弹性的替代方案. 装饰者核心:实现功能组合 继承与组合区别: 继承 继承是给一个类添加行为的比较有效的途径.通过使用继承, ...
- 在linux下利用信号量实现一个写者线程多个读者线程
#include<pthread.h> #include<string.h> #include<stdlib.h> #include<stdio.h> ...
- 数据库数据对比自动生成sql
1.故事背景 有一次迭代步入尾声,提交给用户测试,系统管理员在测试环境中初始了一些数据,然后在上线的时候系统管理员再去正式环境初始这一些数据,然而这次数据太多了,说了一次:”为什么要初始化两次?“ 你 ...
- 基于NIO的Netty网络框架
Netty是一个高性能.异步事件驱动的NIO框架,它提供了对TCP.UDP和文件传输的支持,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者 ...
- String、StringBuffer、StringBuilder比较
String.StringBuffer.StringBuilder三者是字符串中重要的内容,也是面试过程中经常问到的问题,下面就来总结一下三者的区别. 1.三者都可以存储和操作字符串. 2.Strin ...
- Dojo初探之1:AMD规范,编写符合AMD规范(异步模块加载机制)的模块化JS(其中dojo采用1.11.2版本)
一.AMD规范探索 1.AMD规范(即异步模块加载机制) 我们在接触js的时候,一般都是通过各种function来定义一些方法,让它们帮我们做一些事情,一个js可以包含很多个js,而这些functio ...
- JavaScript中对事件简单的理解(1)
事件(event) 1.什么是JavaScript事件? 事件是文档或浏览器中发生的特定交互瞬间. 2.事件流 事件流描述的是从页面中接受事件的顺序,包含IE提出的事件冒泡流与Netscape提出的事 ...
- Ajax&jQuery教案总结
Ajax&jQuery教程总结 目录 第一章 Ajax入门 6 第1讲 传统表单提交存在的问题 6 课程内容 6 1. 问题的引入 6 2. 问题的解决 6 参考进度(0.5课时) 7 第2讲 ...