1、问题引入

实现线程:

public class ThreadDemo implements Runnable
{private boolean flag = false;@Overridepublic void run(){flag = true;System.out.println("flag=" + flag);}public boolean isFlag(){return flag;}public void setFlag(boolean flag){this.flag = flag;}
}

测试类:

public class VolatileTest
{public static void main(String[] args){ThreadDemo threadDemo = new ThreadDemo();new Thread(threadDemo).start();while (true){if(threadDemo.isFlag()){System.out.println("----------------");break;}}}
}

结果:flag=true,并且程序不会停止

结果分析:从结果中看到,线程threadDemo 将 flag 被修改为 ture 了,但是 while 循环中的 if 判断中没有进入(即 flag = false);主线程中的flag和threadDemo 中的flag值不一样。

内存可见性的问题:多个线程操作共享数据时,各个线程之间的数据不一致;

  JVM会为每个线程分配一个独立的缓存用于提高效率。

(1)程序开始运行时主存中的flag=false;

(2)接着线程threadDemo会修改flag数据:threadDemo先从主存中获取到flag数据(false),然后在线程threadDemo中的缓存数据修改为true;

(3)在这个时候main线程来了,main线程从主存中读取到的flag=false;

(4)线程threadDemo将flag=true写入到主存中;

(5)while(true) 的执行效率特别高,以至于 main 线程没有机会从主存中读取数据;

解决内存可见性的问题

1、增加同步锁,用 synchronized 进行同步,代码如下:

public class VolatileTest
{public static void main(String[] args){ThreadDemo threadDemo = new ThreadDemo();new Thread(threadDemo).start();while (true){synchronized (threadDemo){if (threadDemo.isFlag()){System.out.println("----------------");break;}}}}
}

以上代码存在的问题:增加同步锁解决了内存可见性的问题,但是效率特别低;

2、增加 volatile 关键字,修饰线程的共享数据,代码如下:

public class ThreadDemo implements Runnable
{private volatile boolean flag = false;@Overridepublic void run(){flag = true;System.out.println("flag=" + flag);}public boolean isFlag(){return flag;}public void setFlag(boolean flag){this.flag = flag;}
}

 Volatile关键字不具备“互斥性”,Volatile不能保证“原子性”;

Java内存模型(Java Memory Model)描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取出变量这样的底层细节。
    所有的变量都存储在主内存中。每个线程都有自己独立的工作内存,里面保存该线程使用到的变量的副本(主内存中该变量的一份拷贝),如图

两条规定:

  • 线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从主内存中读取
  • 不同线程之间无法直接访问其他线程工作内存中的变量,线程间变量值的传递需要通过主内存来完成。

在这种模型下会存在一个现象,即缓存中的数据与主内存的数据并不是实时同步的,各CPU(或CPU核心)间缓存的数据也不是实时同步的。这导致在同一个时间点,各CPU所看到同一内存地址的数据的值可能是不一致。

volatile关键字
  能够保证volatile变量的可见性,不能保证volatile变量复合操作的原子

volatile如何实现内存的可见性:

深入来说:通过加入内存屏障和禁止重排序优化来实现的
  在每个volatile写操作前插入StoreStore屏障,在写操作后插入StoreLoad屏障;
  在每个volatile读操作前插入LoadLoad屏障,在读操作后插入LoadStore屏障;

通俗地讲:volatile变量在每次被线程访问时,都强迫从主内存中重读该变量的值,而当该变量发生变化时,又会强迫将最新的值刷新到主内存。这样任何时刻,不同的线程总能看到该变量的最新值。

线程volatile变量的过程:
(1)改变线程工作内存中volatile变量副本的值
(2)将改变后的副本的值从工作内存刷新到主内存

线程volatile变量的过程:
(2)从主内存中读取volatile变量的最新值到线程的工作内存中
(2)从工作内存中读取volatile变量的副本

 参考链接:

https://www.cnblogs.com/amei0/p/8378625.html

转载于:https://www.cnblogs.com/yufeng218/p/10116595.html

Volatile 关键字 内存可见性相关推荐

  1. 24.volatile关键字的作用、volatile原理、可见性、内存屏障、volatile性能、transient

    24.volatile关键字的作用 24.1.volatile原理 24.2.可见性 24.3.内存屏障 24.4.volatile性能 25.transient 24.volatile关键字的作用 ...

  2. 内存可见性和原子性:Synchronized和Volatile的比较

    Java多线程之内存可见性和原子性:Synchronized和Volatile的比较     [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article ...

  3. 一文读懂Java内存模型(JMM)及volatile关键字

    点赞再看,养成习惯,公众号搜一搜[一角钱技术]关注更多原创技术文章. 本文 GitHub org_hejianhui/JavaStudy 已收录,有我的系列文章. 前言 并发编程从操作系统底层工作的整 ...

  4. 全面理解Java内存模型(JMM)及volatile关键字

    [版权申明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/72772461 出自[zejian ...

  5. 爆赞,对 volatile 关键字讲解最好的一篇文章!

    欢迎关注方志朋的博客,回复"666"获面试宝典 最近,在一篇文章中了解到了 volatile 关键字,在强烈的求知欲趋使下,我查阅了一些相关资料进行了学习,并将学习笔记记录如下,希 ...

  6. volatile关键字的作用、原理

    在只有双重检查锁,没有volatile的懒加载单例模式中,由于指令重排序的问题,我确实不会拿到两个不同的单例了,但我会拿到"半个"单例. 而发挥神奇作用的volatile,可以当之 ...

  7. volatile关键字和AtomicInteger

    在Java中,线程部分是一个重点,本篇文章说的JUC也是关于线程的.JUC就是java.util .concurrent工具包的简称.这是一个处理线程的工具包,JDK 1.5开始出现的.下面一起来看看 ...

  8. volatile关键字的作用-适用场景

    volatile在Java并发编程中常用于保持内存可见性和防止指令重排序.内存可见性(Memory Visibility):所有线程都能看到共享内存的最新状态:防止指令重排:在基于偏序关系的Happe ...

  9. 【Java线程】深入理解Volatile关键字和使用

    目录 背景 volatile原理 volatile特性 可见性 有序性 原子性 使用场景 背景 理解volatile底层原理之前,首先介绍关于缓存一致性协议的知识. 背景:计算机在执行程序时,每条指令 ...

最新文章

  1. JS 获取中英字符串字节长度
  2. mysql开发java心得_关于mysql 一些优化心得
  3. Ubuntu虚拟机磁盘扩容+VM虚拟机开机多出1分30秒的解决方案(终极教程)
  4. shell管道重定向程序的实现
  5. 批量修改Dell服务器远程管理卡iDRAC密码
  6. 核心编程第五版 配套代码_攻略Python的免费书单:走进编程,从这五本书开始...
  7. ping 丢包 网络摄像头_FIFA21 新加入网络连接监测功能
  8. OpenSSL版本号
  9. PowerDesigner设置code和name不联动的方法
  10. 消息队列 (1) mac安装RabbitMQ
  11. Dorado7之AjaxAction
  12. 苹果怎么用测试软件,iPhone 也能测量身高教你怎么用 iOS「测距仪」App
  13. flashfxp配置文件服务器同步,如何导出FlashFXP的站点配置文件
  14. Fuzzy set基本介绍(1)
  15. 从C端市场延伸至B端业务拓展,流利说深耕行业英语价值几何?
  16. 系统集成15真题解析
  17. 【解惑】杨中科说给弟弟的话
  18. 基于JSP的煤炭销售系统,源码下载
  19. Struts2类型转换的说明及案例分析
  20. 【IT简史】IBM(国际商业机器公司)

热门文章

  1. Java 多线程断点下载文件_详解
  2. HttpClient+jsoup登录+解析 163邮箱
  3. Node.js的安装
  4. Android视图绘制流程完全解析,带你一步步深入了解View(二)
  5. 浏览器对象模型BOM
  6. C语言中不安全的函数
  7. muduo:高效整型转换为字符串
  8. 多传感器信息融合算法总结
  9. shell实例第0讲:shell脚本完整pdf文档下载
  10. 用IAR调试程序时直接跳过断点执行后面程序的解决办法