先来看一个例子:

  1. public class VolatileTest {  
  2.     
  3.     public static void main(String[] args) {  
  4.         ThreadDemo td = new ThreadDemo();  
  5.         new Thread(td).start();  
  6.     
  7.         while (true) {  
  8.             if (td.isFlag()) {  
  9.                 System.out.println("================");  
  10.                 break;  
  11.             }  
  12.         }  
  13.     }  
  14. }  
  15.     
  16. class ThreadDemo implements Runnable {  
  17.     private boolean flag = false;  
  18.     
  19.     @Override  
  20.     public void run() {  
  21.         try {  
  22.             Thread.sleep(200);  
  23.         } catch (InterruptedException e) {  
  24.     
  25.         }  
  26.         flag = true;  
  27.         System.out.println("falg=" + flag);  
  28.     }  
  29.     
  30.     public boolean isFlag() {  
  31.         return flag;  
  32.     }  
  33.     
  34.     public void setFlag(boolean flag) {  
  35.         this.flag = flag;  
  36.     }  
  37. }  

两个线程,一个改flag的值,主线程做判断,结果:

主线程的flag貌似还是false,按理通过Runnable创建的线程访问的应该是共享数据,那为什么会出现这种情况?这就涉及到内存可见性。

JVM会为每个线程分配一个独立缓存提高效率。上述例子中我们先在主存中开辟一块内存,如图:

那么这个两个线程,一个是读(主线程),一个是写(线程1),我们让线程1睡了200ms,说明,线程1先执行,每个线程都有一个独立的缓存,也就是说当线程1需要对主存的共享数值进行改变,它需要先把这个flag复制一份到缓存区中,

然后修改,将来再把这个值写回主存去,在写之前,主线程来了,它要读取现在在内存里面的值,现在是false,当然有一种情况,就是线程1在某个机会将flag=true写回去,

当时主线程用了while(true),这句话调用了系统底层代码,效率极高,高到主线程没有机会再次读取内存,这就是线程对共享数据操作的不可见。

内存可见性问题:当多个线程操作共享数据时,彼此不可见。

如何解决?同步锁。

但是用了锁,代表效率极低,但是我现在我不想加锁,但是有存在内存可见性的问题,我该怎么办?

关键字volatile:当多个线程进行操作共享操作时,可以保证内存中的数据可见。(内存栅栏,实时刷新)

我们可以认为它是直接在主存操作的,这个实时刷新的操作相比不加,性能略低,但是比加锁的效率显然高很多,低在哪?加了这关键字,JVM就不能进行指令重排序,无法优化代码执行。

  1. public class VolatileTest {  
  2.     
  3.     public static void main(String[] args) {  
  4.         ThreadDemo td = new ThreadDemo();  
  5.         new Thread(td).start();  
  6.     
  7.         while (true) {  
  8.             if (td.isFlag()) {  
  9.                 System.out.println("================");  
  10.                 break;  
  11.             }  
  12.         }  
  13.     }  
  14. }  
  15.     
  16. class ThreadDemo implements Runnable {  
  17.     private volatile boolean flag = false;  
  18.     
  19.     @Override  
  20.     public void run() {  
  21.         try {  
  22.             Thread.sleep(200);  
  23.         } catch (InterruptedException e) {  
  24.     
  25.         }  
  26.         flag = true;  
  27.         System.out.println("falg=" + flag);  
  28.     }  
  29.     
  30.     public boolean isFlag() {  
  31.         return flag;  
  32.     }  
  33.     
  34.     public void setFlag(boolean flag) {  
  35.         this.flag = flag;  
  36.     }  
  37. }  

volatile相对synchronized是一种轻量级同步策略。但是注意:

  1. volatile不具备互斥性
  2. volatile不能保证变量的原子性

详解volatile 关键字与内存可见性的更多相关文章

  1. volatile关键字与内存可见性

    前言 首先,我们使用多线程的目的在于提高程序的效率,但是如果使用不当,不仅不能提高效率,反而会使程序的性能更低,因为多线程涉及到线程之间的调度.CPU上下文的切换以及包括线程的创建.销毁和同步等等,开 ...

  2. volatile关键字与内存可见性&原子变量与CAS算法

    1 .volatile 关键字:当多个线程进行操作共享数据时, 可以保证内存中的数据可见 2 .原子变量:jdk1.5后java.util.concurrent.atomic 包下提供常用的原子变量 ...

  3. 详解 volatile关键字 与 CAS算法

    (请观看本人博文 -- <详解 多线程>) 目录 内存可见性问题 volatile关键字 CAS算法: 扩展 -- 乐观锁 与 悲观锁: 悲观锁: 乐观锁: 在讲解本篇博文的知识点之前,本 ...

  4. 【JUC系列第一篇】-Volatile关键字及内存可见性

    作者:毕来生 微信:878799579 什么是JUC? JUC全称 java.util.concurrent 是在并发编程中很常用的实用工具类 2.Volatile关键字 1.如果一个变量被volat ...

  5. 详解volatile关键字和原子引用

    本篇看一下Volatile关键字和原子引用. 上图就是JUC包结构,总共分成三块 (1)java.util.concurrent:并发包基础类,包括阻塞队列,线程池相关类,线程安全Map等. (2)j ...

  6. volatile关键字及内存可见性

    先看一段代码: package com.java.juc; public class TestVolatile { public static void main(String[] args) { T ...

  7. java 轻量级同步volatile关键字简介与可见性有序性与synchronized区别 多线程中篇(十二)

    概念 JMM规范解决了线程安全的问题,主要三个方面:原子性.可见性.有序性,借助于synchronized关键字体现,可以有效地保障线程安全(前提是你正确运用) 之前说过,这三个特性并不一定需要全部同 ...

  8. 【Java并发编程】6、volatile关键字解析&内存模型&并发编程中三概念

    volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以 ...

  9. volatile关键字解析&内存模型&并发编程中三概念

    原文链接: http://www.cnblogs.com/dolphin0520/p/3920373.html volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java5之前,它是一个 ...

随机推荐

  1. 流水车间调度算法分析的简单+Leapms实践--混合整数规划的启发式建模

    流水车间调度算法分析的简单+Leapms实践--混合整数规划的启发式建模 清华大学出版社出版的白丹宇教授著作<流水车间与开放车间调度算法渐近分析>采用渐近分析方法分析多个NP-难类启发调度 ...

  2. 1.3创建项目「深入浅出ASP.NET Core系列」

    控制台创建项目 dotnet new --help 使用控制台采集项目,务必要熟练使用命令,--help是命令帮助的指明灯,在你无法google的时候,可以离线状态最快的帮助到你. 根据模板名称,我们 ...

  3. java 并发多线程显式锁概念简介 什么是显式锁 多线程下篇(一)

    目前对于同步,仅仅介绍了一个关键字synchronized,可以用于保证线程同步的原子性.可见性.有序性 对于synchronized关键字,对于静态方法默认是以该类的class对象作为锁,对于实例方 ...

  4. Springboot 系列(五)Spring Boot web 开发之静态资源和模版引擎

    前言 Spring Boot 天生的适合 web 应用开发,它可以快速的嵌入 Tomcat, Jetty 或 Netty 用于包含一个 HTTP 服务器.且开发十分简单,只需要引入 web 开发所需的 ...

  5. 【带着canvas去流浪(7)】绘制水球图

    目录 一. 任务说明 二. 重点提示 三. 示例代码 四. 文字淹水效果的实现 五. 关于canvas抗锯齿 六. 小结 示例代码托管在:http://www.github.com/dashnowor ...

  6. MySQL InnoDB 存储引擎探秘

    在MySQL中InnoDB属于存储引擎层,并以插件的形式集成在数据库中.从MySQL5.5.8开始,InnoDB成为其默认的存储引擎.InnoDB存储引擎支持事务.其设计目标主要是面向OLTP的应用, ...

  7. js 3D旋转效果

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. 生鲜配送管理系统_升鲜宝供应链系统V2.0 设计思想及主要模块,欢迎大家批评指点。

    前言: 经过这几年的开发,升鲜宝生鲜供应链系统管理软件,终于完成C/S与B/S二个版本的开发,先主要介绍B/S版本的功能,C/S版本的功能更加完善. 升鲜宝供应链系统主要由以下几个主要端组成:     ...

  9. lock了mutex的线程退出了却没有unlock时会怎么样?

    https://stackoverflow.com/questions/4424193/what-happens-to-mutex-when-the-thread-which-acquired-it- ...

  10. datatable的部分问题处理(动态定义列头,给某行添加事件,初始显示空数据)

    一.动态定义列头 在ajax中,用datatable再去重新配置列头,当然传回的数据中,要有对应放列头的键值对 我自定义了Mock数据,用于前端自己交互. 其中,rowdata用于存放传回的数据,co ...