Java多线程-----volatile关键字详解
volatile原理
Java语言提供了一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程。当把变量声明为volatile类型后,
编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄
存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值
当对非 volatile 变量进行读写的时候,每个线程先从内存拷贝变量到CPU缓存中。如果计算机有多个CPU,每个线程可能在不同的CPU
上被处理,这意味着每个线程可以拷贝到不同的 CPU cache 中。而声明变量是 volatile 的,JVM 保证了每次读变量都从内存中读。
当一个变量定义为 volatile 之后,将具备两种特性:
1.保证此变量对所有的线程的可见性,这里的“可见性”,指当一个线程修改了这个变量的值,volatile 保证了新值能立即同步到主内存,
以及每次使用前立即从主内存刷新。但普通变量做不到这点,普通变量的值在线程间传递均需要通过主内存来完成,即复制变量值到当前线
程缓存中修改,然后再返回给主内存。
2.禁止指令重排序优化。什么是指令重排序:是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理。
并发编程的三个特性
1.原子性
原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行
2.可见性
可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值
//线程1执行的代码
int i = 0;
i = 10; //线程2执行的代码
j = i;
当线程1执行 i =10这句时,会先把i的初始值加载到CPU1的高速缓存中,然后赋值为10,那么在CPU1的高速缓存当中i的值变为10了,却没有立即写入到主存当中。
此时线程2执行 j = i,它会先去主存读取i的值并加载到CPU2的缓存当中,注意此时内存当中i的值还是0,那么就会使得j的值为0,而不是10.
这就是可见性问题,线程1对变量i修改了之后,线程2没有立即看到线程1修改的值。
3.有序性
有序性:即程序执行的顺序按照代码的先后顺序执行
int i = 0;
int j = 0;
i = 10; //语句1
j = 1; //语句2
语句可能的执行顺序如下:
- 1)语句1 语句2
- 2)语句2 语句1
语句1一定在语句2前面执行吗?答案是否定的,这里可能会发生执行重排(Instruction Reorder)。一般来说,处理器为了提高程序运行效率,
可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序在单线程环境下最终执行结果和
代码顺序执行的结果是一致的。
volatile实例
1.变量没有使用volatile关键字
package com.thread.volatileintroduce; /**
* 没有使用Volatile关键字
*
* @author yyx 2019年1月12日
*/
public class NoVolatile {
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
new Thread(td).start(); while (true) {
if (td.isFlag()) {
System.out.println("------------------");
break;
}
}
}
} class ThreadDemo implements Runnable {
private boolean flag = false; @Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
} public boolean isFlag() {
return flag;
} public void setFlag(boolean flag) {
this.flag = flag;
}
}
运行结果:flag=true
主线程不会打印出“--------------”
2.使用volatile关键字
package com.thread.volatileintroduce; /**
* 使用Volatile关键字
* volatile 关键字:当多个线程进行操作共享数据时,可以保证内存中的数据可见。 相较于 synchronized
* 是一种较为轻量级的同步策略。
*
* 注意: 1. volatile 不具备“互斥性” 2. volatile 不能保证变量的“原子性”
*
* @author yyx 2019年1月12日
*/
public class HaveVolatile {
public static void main(String[] args) {
SubThread subThread = new SubThread();
new Thread(subThread).start(); while (true) {
if (subThread.isFlag()) {
System.out.println("------------------");
break;
}
}
}
} class SubThread implements Runnable {
private volatile boolean flag = false; @Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
} public boolean isFlag() {
return flag;
} public void setFlag(boolean flag) {
this.flag = flag;
}
}
运行结果:
flag=true
------------------
注意:volatile不能保证线程的安全
- volatile不具备“互斥性”
- volatile不能保证变量的“原子性”
Java多线程-----volatile关键字详解的更多相关文章
- Java中Volatile关键字详解 (转自郑州的文武)
java中volatile关键字的含义:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html 一.基本概念 先补充一下概念:J ...
- Java中Volatile关键字详解
一.基本概念 先补充一下概念:Java并发中的可见性与原子性 可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值, ...
- Java中Volatile关键字详解(转载)
转载自:https://www.cnblogs.com/zhengbin/p/5654805.html 一.基本概念 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性是 ...
- Java volatile关键字详解
Java volatile关键字详解 volatile是java中的一个关键字,用于修饰变量.被此关键修饰的变量可以禁止对此变量操作的指令进行重排,还有保持内存的可见性. 简言之它的作用就是: 禁止指 ...
- java continue break 关键字 详解 区别 用法 标记 标签 使用 示例 联系
本文关键词: java continue break 关键字 详解 区别 用法 标记 标签 使用 示例 联系 跳出循环 带标签的continue和break 嵌套循环 深入continue ...
- Java之先行发生原则与volatile关键字详解
volatile关键字可以说是Java虚拟机提供的最轻量级的同步机制,但是它并不容易完全被正确.完整地理解,以至于许多程序员都习惯不去使用它,遇到需要处理多线程数据竞争问题的时候一律使用synchro ...
- Java并发编程:JMM (Java内存模型) 以及与volatile关键字详解
目录 计算机系统的一致性 Java内存模型 内存模型的3个重要特征 原子性 可见性 有序性 指令重排序 volatile关键字 保证可见性和防止指令重排 不能保证原子性 计算机系统的一致性 在现代计算 ...
- Java Volatile 关键字详解
原文链接:https://www.cnblogs.com/zhengbin/p/5654805.html 一.基本概念 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性 ...
- jvm运行机制和volatile关键字详解
参考https://www.cnblogs.com/dolphin0520/p/3920373.html JVM启动流程 1.java虚拟机启动的命令是通过java +xxx(类名,这个类中要有mai ...
随机推荐
- 安装 Samba服务
参考摘录的是博客园的文章:https://www.cnblogs.com/zhaopengcheng/p/5481048.html ubuntu系统:16.04 1. 首先用管理员权限创建一个新用户, ...
- 【雅思】【写作】【大作文】Discuss both views and give your own opinion
•Discuss both views and give your own opinion • • •Agree or disagree •Discuss both views •Report ...
- OC屏幕手势解锁
感觉屏幕解锁好像很牛的样子,所以试着写了一个,代码很简单,手势用到的也是原生的,如果该代码帮助了你,记得点赞,如果该代码有任何问题,也可以随时和我联系.改代码用到的两张图片,是我随便找的两张,可以自行 ...
- MySQL中any、some、all关键字
MySQL中any.some.all关键字http://blog.csdn.net/imzoer/article/details/8266324 ANY关键字: 假设any内部的查询语句返回的结果个数 ...
- what's the python之函数及装饰器
what's the 函数? 函数的定义:(return是返回值,可以没有,不过没有的话就返回了None) def wrapper(参数1,参数2,*args,默认参数,**kwargs): '''注 ...
- Dockerfile语法解析
Dockfile介绍 从上到下依次执行 每次执行一条指令就创建一个镜像层 第一条指令必须是FROM 表示需要构建的镜像是由哪个镜像为基础镜像 后续的指令运行于此基准镜像所提供的运行环境 可以 ...
- ansible进阶模板和角色使用
使用场景 Ansible 由于采用ssh远程连接登录管理,虽然不需要额外安装agent,但是速度慢效率低.不适合管理大规模的主机一般最大规模在200-300台,超大规模的主机管理适合使用puppet ...
- Visual Studio使用Web Deploy远程发布网站及其配置
https://blog.csdn.net/yzj_xiaoyue/article/details/60574378 废话不多说,直接进入正题(各个步骤请看图片的序号): IIS配置 1.打开服务器 ...
- JavaScript 全栈工程师培训教程 - 阮一峰
http://www.ruanyifeng.com/blog/2016/11/javascript.html https://github.com/ruanyf/jstraining 我现在的技术方向 ...
- 调用run与调用start的区别
调用start的结果 package TestException; public class test1 { public static void main(String[] args) { // 3 ...