之前在InfoQ看到一篇关于java重排序的一篇文章,觉得里面有些知识写得太绝对了,于是想通过实际程序来说明一下:

关于java重排序,这里就不做介绍了,我们知道JVM底层封装了与OS的交互,它内部有自己的一套类似于OS的内存模型,程序重排序的设计思路基本上是来源于OS跟硬件层面的设计。下面直接入正题吧!

我们知道JVM给每个线程分配了自己的内存空间,也就是说在变量存储方面,分为主内存和线程工作内存,也就是说,所有线程共享主内存,每个线程都有自己的工作内存。程序执行的时候是去工作内存里面取值还是去主内存里面取值呢?下面以代码为例:

public class DemoWork {private boolean stop=false;private boolean start=true;public void workThread() throws InterruptedException{Thread workThread=new Thread(new Runnable() {private int i=0;@Overridepublic void run() {// TODO Auto-generated method stubwhile(!stop){i++;/*try {Thread.sleep(10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}*/}start=false;}});workThread.start();Thread.sleep(1000);stop=true;Thread printThread=new Thread(new Runnable() {private int i=0;@Overridepublic void run() {// TODO Auto-generated method stubwhile(stop&&start){System.out.println("stop is:"+stop);try {Thread.sleep(10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}});printThread.start();}/*** @param args* @throws InterruptedException */public static void main(String[] args) throws InterruptedException {// TODO Auto-generated method stubDemoWork dw=new DemoWork();dw.workThread();}}

上面的代码是不会停下来的,但是如果把sleep那段代码的注释去掉程序就能停下来了,这是什么原因呢?我的理解是:因为线程printThread是能正常执行的,所以有两种可能:

  • 线程workThread里面工作线程stop变量值没有收到主存的同步,而它一直取的是自己工作线程里面的stop值

  • 主线程更新stop没有更新主内存,以至于主内存里面保存的stop值一直是false

以上第二点我觉得是可以排除的,因为线程printThread里面的值stop值是true,所以造成以上情况第一点的可能性大一点,那为什么把workThread里面的睡眠去掉之后程序又能正常退出呢?那就应该是在执行这些语句的时候主内存更新了工作内存的缘故了(执行打印语句也会推出,至于这里面的原因是什么,暂时还没看到相关的资料,可能跟JVM的重排序规则有关系,但是规则到底是怎样的呢?),接下来我们来说说volatile。

volatile:

  1. (适用于Java所有版本)读和写一个volatile变量有全局的排序。也就是说每个线程访问一个volatile作用域时会在继续执行之前读取它的当前值,而不是(可能)使用一个缓存的值。(但是并不保证经常读写volatile作用域时读和写的相对顺序,也就是说通常这并不是有用的线程构建)。

  2. (适用于Java5及其之后的版本)volatile的读和写建立了一个happens-before关系,类似于申请和释放一个互斥锁[7]。

也就是说在上面workThread线程sleep代码段注释的情况下,我们可以使用volatile来修饰stop变量,这样的话就能强制workThread线程去主内存里面取stop的值了,但是这样做的话在高并发现会造成性能问题。之前看了很多的开源代码,里面解决以上主内存与工作内存不同步的方式基本上是采用volatile修饰变量解决的。我在想,既然volatile在并发情况下会造成性能问题,在workThread循环快里面执行什么类型的代码快能方便JVM更好的同步主内存跟工作内存的值,那样的话,在高并发下,就能更快的提高程序性能了。

转载于:https://blog.51cto.com/chenyanxi/1577101

为了防止程序重排序,慎用volatile相关推荐

  1. 【Java 并发编程】线程指令重排序问题 ( 指令重排序规范 | volatile 关键字禁止指令重排序 )

    文章目录 总结 一.指令重排序规范 二.指令重排序示例 总结 Java 并发的 333 特性 : 原子性 : 每个操作都是 不可拆分的原子操作 ; 在线程中进行 a++ 就不是原子操作 , 该操作分为 ...

  2. Volatile重排序规则的一些理解

    volatile的内存语义 volatile的特性 可见性 : 对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入 原子性 禁止重排序 本文主要想讨论一下vol ...

  3. Java内存访问重排序的研究

    什么是重排序 请先看这样一段代码1 public class PossibleReordering { static int x = 0, y = 0; static int a = 0, b = 0 ...

  4. 由Java引起的指令重排序思考

    背景 问题出现 最近遇到了一个NullPointerException,虽然量不大,但是很怪异,大致长这个样子 这是个什么空指针?居然说我LinkedList.iterator().hasNext() ...

  5. 什么是指令重排序和内存屏障,看完你就懂了

    面试官在问到多线程编程的时候,指令重排序.内存屏障经常会被提起.如果你对这两者有一定的理解,那这就是你的加分项. (一)什么是指令重排序 为了使处理器内部的运算单元能尽量被充分利用,处理器可能会对输入 ...

  6. Java之内存模型的基础、重排序、顺序一致性、volatile、锁、final

    为什么80%的码农都做不了架构师?>>>    深入理解Java内存模型(一)--基础 深入理解Java内存模型(二)--重排序 深入理解Java内存模型(三)--顺序一致性 深入理 ...

  7. Java之volatile如何保证可见性和指令重排序

    1 我们先了解CPU缓存 CPU缓存为了解决CPU运算速度与内存读写速度不匹配的问题,因为CPU运算速度要比内存读写速度快得多 一次主内存的访问通常在几十到几百个时钟周期 一次L1高速缓存的读写只需要 ...

  8. 指令重排序所带来的问题及使用volatile关键字解决问题

    首先看下如下代码: 指令重排序和优化后代码如下: if(!stop) while(true){} volatile最适合使用的是一个线程写.其他线程读的场合,如果有多个线程并发写操作,仍然需要使用锁或 ...

  9. Java的多线程机制系列:(四)不得不提的volatile及指令重排序(happen-before)

    一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专 ...

最新文章

  1. 规范性分析是不是产生最优业务成果的处方?
  2. matlab 文件路径问题
  3. android get请求最长字符串,android – Retrofit @GET – 如何显示请求字符串?
  4. mysql - 要问 varchar 能存几个汉字? 能存几个 字母? 能存几个数字?请看下文讲解 (Java)
  5. springmvc 传对象报400_那么火的SpringMVC到底有什么过人之处呢
  6. 《纵向切入ASP.NET 3.5控件和组件开发技术》笔记:高效率事件集合对象
  7. Windows Management Framework 中修改WinRM监听端口
  8. 51 NOD 1013 3的幂的和
  9. 安卓帧数监测软件_安卓查看帧数的软件
  10. trend函数用oracle实现,Excel函数TREND函数的用法
  11. docker打包部署微服务项目
  12. list去重及求两个list中元素的重复率
  13. 11.3 leetcode打卡
  14. cocos creator如何实现微信好友自定义转发分享功能
  15. 小米android隐藏游戏,MIUI8小米手机开启隐藏选项
  16. 说一说TS码流里面的PCR
  17. 什么是视图?为什么使用视图?如何创建一个视图?视图的分类?
  18. BOLL布林带定向策略
  19. UGUI-- 图集制作
  20. 防坑指南: 杨工告诉你免联考国际硕士到底是个什么梗?

热门文章

  1. Qt:Qt实现网页自动刷新工具
  2. java课程之团队开发冲刺阶段1.7
  3. Two sum(给定一个无重复数组和目标值,查找数组中和为目标值的两个数,并输出其下标)...
  4. 【python】-- IO多路复用(select、poll、epoll)介绍及实现
  5. kaili camera
  6. pat00-自测2. 素数对猜想 (20)
  7. 20 个强大的 Sublime Text 插件
  8. 抖音封杀小猪佩奇,一年赚100亿的“社会人”得罪了谁?
  9. 这样的问题代码,我实习的时候都写不出来!
  10. Java程序员必备:常见OOM异常分析