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关键字详解的更多相关文章

  1. Java中Volatile关键字详解 (转自郑州的文武)

    java中volatile关键字的含义:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html 一.基本概念 先补充一下概念:J ...

  2. Java中Volatile关键字详解

    一.基本概念 先补充一下概念:Java并发中的可见性与原子性 可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值, ...

  3. Java中Volatile关键字详解(转载)

    转载自:https://www.cnblogs.com/zhengbin/p/5654805.html 一.基本概念 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性是 ...

  4. Java volatile关键字详解

    Java volatile关键字详解 volatile是java中的一个关键字,用于修饰变量.被此关键修饰的变量可以禁止对此变量操作的指令进行重排,还有保持内存的可见性. 简言之它的作用就是: 禁止指 ...

  5. java continue break 关键字 详解 区别 用法 标记 标签 使用 示例 联系

    本文关键词: java continue break 关键字 详解 区别  用法 标记  标签 使用 示例 联系   跳出循环 带标签的continue和break 嵌套循环  深入continue ...

  6. Java之先行发生原则与volatile关键字详解

    volatile关键字可以说是Java虚拟机提供的最轻量级的同步机制,但是它并不容易完全被正确.完整地理解,以至于许多程序员都习惯不去使用它,遇到需要处理多线程数据竞争问题的时候一律使用synchro ...

  7. Java并发编程:JMM (Java内存模型) 以及与volatile关键字详解

    目录 计算机系统的一致性 Java内存模型 内存模型的3个重要特征 原子性 可见性 有序性 指令重排序 volatile关键字 保证可见性和防止指令重排 不能保证原子性 计算机系统的一致性 在现代计算 ...

  8. Java Volatile 关键字详解

    原文链接:https://www.cnblogs.com/zhengbin/p/5654805.html 一.基本概念 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性 ...

  9. jvm运行机制和volatile关键字详解

    参考https://www.cnblogs.com/dolphin0520/p/3920373.html JVM启动流程 1.java虚拟机启动的命令是通过java +xxx(类名,这个类中要有mai ...

随机推荐

  1. MonkeyRunner_模拟机_运行脚本

    1.打开创建好的Android模拟机  (使用AVD Manager.exe打开,或者使用cmd窗口 emulator -avd test2打开) 2.打开cmd窗口,输入monkeyrunner,然 ...

  2. xca自签发证书解决chrome浏览器证书不可信问题记录

    xca打开的界面 依次File, New DataBase,选择xdb文件保存路径,再输入密码 切换到Certificates页面,点击New Certificate 出现如下界面 因为要创建根证书, ...

  3. es组合多个条件进行查询

    GET /test_index/_search{ "query": { "bool": { "must": { "match&qu ...

  4. Docker 架构(四)

    Docker 使用客户端-服务器 (C/S) 架构模式,使用远程 API 来管理和创建 Docker 容器. Docker 容器通过 Docker 镜像来创建. 容器与镜像的关系类似于面向对象编程中的 ...

  5. jquery 请求返回的几种方式

    页面代码 <form id="form1" runat="server"> <div> <p> Ajax请求ashx返回js ...

  6. 帝国cms搜索关键字调用标签(showsearch)怎么用

    前面ytkah介绍了如何让帝国CMS7.2搜索模板支持动态标签调用,现在我们来说说怎么调用帝国cms搜索关键字调用标签(showsearch).在帝国cms后台那边的使用方法:[showsearch] ...

  7. hdu1240/poj2225 BFS广搜的再理解

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/guodongxiaren/article/details/37756347 原题地址 pid=124 ...

  8. MathWorks.MATLAB.NET.Arrays.MWArray”的类型初始值设定项引发异常 解决方法

    原因 用的是matlab7运行时,后面又安装了matlab11,后面又重新安装了matlab7运行时,c盘下就有二个运行时的版本了,程序引用了后面的那个,编译后就出上面的问题 解决方法 1重新引用上面 ...

  9. warning: LF will be replaced by CRLF in 解决办法

    今天用Git bash遇到的问题,看了几个回答之后发现一个比较有价值的,给大家分享一下,其他很多的回答都有很或多或少存在一些弊端. 原回答地址在stackoverflow上,附上链接--http:// ...

  10. 通过socket实现http通讯代码理解

    1.首先构造http协议报头: String dd = "GET http://www.baidu.com HTTP/1.1" + "\r\n" + " ...