总览

许多多线程代码开发人员都熟悉这样的想法,即不同的线程可以对持有的值有不同的看法,这不是唯一的原因,即如果线程不安全,它可能不会看到更改。 JIT本身可以发挥作用。

为什么不同的线程看到不同的值?

当您有多个线程时,它们将尝试例如通过尝试访问同一内存来最小化它们将交互的数量。 为此,他们有一个单独的
本地副本,例如在1级缓存中。 该缓存通常最终是一致的。 我看到两个线程看到不同值的短时间介于一微秒到十毫秒之间。 最终,线程被上下文切换,缓存被清除或更新。 无法保证何时会发生这种情况,但几乎总是不到一秒钟。

JIT如何发挥作用?

Java内存模型说,不能保证不是线程安全的字段将看到更新。 这允许JIT进行优化,将仅读取而不写入的值有效地内联到代码中。 这意味着即使更新了缓存,更改也可能不会反映在代码中。

一个例子

该代码将一直运行,直到将布尔值设置为false为止。

>static class MyTask implements Runnable {private final int loopTimes;private boolean running = true;boolean stopped = false;public MyTask(int loopTimes) {this.loopTimes = loopTimes;}@Overridepublic void run() {try {while (running) {longCalculation();}} finally {stopped = true;}}private void longCalculation() {for (int i = 1; i < loopTimes; i++)if (Math.log10(i) < 0)throw new AssertionError();}
}public static void main(String... args) throws InterruptedException {int loopTimes = Integer.parseInt(args[0]);MyTask task = new MyTask(loopTimes);Thread thread = new Thread(task);thread.setDaemon(true);thread.start();TimeUnit.MILLISECONDS.sleep(100);task.running = false;for (int i = 0; i < 200; i++) {TimeUnit.MILLISECONDS.sleep(500);System.out.println("stopped = " + task.stopped);if (task.stopped)break;}
}

此代码反复执行一些对内存没有影响的工作。 它唯一的区别是需要多长时间。 通过花费更长的时间,它将确定在运行之前或之后将run()中的代码优化为false。

如果我使用10或100和-XX:+ PrintCompilation运行此命令,则会看到

111    1     java.lang.String::hashCode (55 bytes)
112    2     java.lang.String::charAt (29 bytes)
135    3     vanilla.java.perfeg.threads.OptimisationMain$MyTask :longCalculation (35 bytes)
204    1 % ! vanilla.java.perfeg.threads.OptimisationMain$MyTask :run @ 0 (31 bytes)
stopped = false
stopped = false
stopped = false
stopped = false
... many deleted ...
stopped = false
stopped = false
stopped = false
stopped = false
stopped = false

如果我用1000运行它,您会看到run()尚未编译并且线程停止

112    1     java.lang.String::hashCode (55 bytes)
112    2     java.lang.String::charAt (29 bytes)
133    3     vanilla.java.perfeg.threads.OptimisationMain $MyTask::longCalculation (35 bytes)
135    1 %   vanilla.java.perfeg.threads.OptimisationMain $MyTask::longCalculation @ 2 (35 bytes)
stopped = true

一旦线程被编译,即使线程将进行多次上下文切换等,更改也永远不会被看到。

如何解决这个问题

简单的解决方案是使该字段易变。 这将确保该字段的值是一致的,而不仅仅是最终一致的,这就是缓存可能为您执行的操作。

结论

虽然有许多类似的问题示例; 为什么我的线程没有停止? 答案更多与Java内存模型有关,Java内存模型允许JIT“内联”它执行硬件的字段,并在不同的缓存中具有多个数据副本。

参考: Vanilla Java博客上的JCG合作伙伴 Peter Lawrey提供的Java内存模型和优化 。

翻译自: https://www.javacodegeeks.com/2013/01/java-memory-model-and-optimisation-2.html

Java内存模型和优化相关推荐

  1. java内存模型和内存结构_Java内存模型和优化

    java内存模型和内存结构 总览 许多多线程代码开发人员都熟悉这样的想法,即不同的线程可以对持有的值有不同的看法,这不是唯一的原因,即如果线程不安全,它可能不会看到更改. JIT本身可以发挥作用. 为 ...

  2. 从底层吃透java内存模型(JMM)、volatile、CAS

    前言 随着计算机的飞速发展,cpu从单核到四核,八核.在2020年中国网民数预计将达到11亿人.这些数据都意味着,作为一名java程序员,必须要掌握多线程开发,谈及多线程,绕不开的是对JMM(Java ...

  3. 循序渐进:带你理解什么是Java内存模型

    近期笔者在阅读<深入理解Java虚拟机:JVM高级特性与最佳实现(第3版)>,书中提到关于Java内存模型的知识点,但是看完之后还是感觉有些模糊,便查阅一些其他相关资料.本文是笔者经过对知 ...

  4. JSR 133 Java内存模型以及并发编程的最权威论文汇总

    Java内存模型 先看官方文档: https://docs.oracle.com/javase/specs/ JSR 133:Java TM内存模型和线程规范修订版:https://www.jcp.o ...

  5. java线程的优先级是数字越大优先级越高_《深入理解Java虚拟机》5分钟速成:12章(Java内存模型与线程)...

    第12章 Java内存模型与线程 前言: 1.物理机如何处理并发问题? 2.什么是Java内存模型? 3.原子性.可见性.有序性的具体含义和应用实现? 4.volatile 关键字特性? 5.基于vo ...

  6. Java内存模型与线程

    一.一致性 高速缓存的存储交互很好的解决了处理器与内存的速度矛盾,但也存在缓存一致性(cache coherence)问题 二.java内存模型 内存模型:对特定的内存或高速缓存进行读写访问的过程抽象 ...

  7. 深入理解Java内存模型(四)——volatile

    2019独角兽企业重金招聘Python工程师标准>>> volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解volatile特性的一个好 ...

  8. 也许,这是东半球最叼的Java内存模型

    面试官:你好,你先自我介绍一下. 安琪拉:面试官你好,我叫安琪拉,草丛三婊,最强中单,草地摩托车车手,第21套广播体操推广者,火球拥有者.不焚者,安琪拉,这是我的简历,请过目. 面试官:看你简历上写熟 ...

  9. 并发编程专题——第一章(深入理解java内存模型)

    说到并发编程,其实有时候觉得,开发中真遇到这些所谓的并发编程,场景多吗,这应该是很多互联网的在职人员,一直在考虑的事情,也一直很想问,但是又不敢问,想学习的同时,网上这些讲的又是乱七八糟,那么本章开始 ...

最新文章

  1. C#利用Graphics类绘制进阶--实现图片等比例缩放
  2. 人类首次商业太空行走敲定!马斯克SpaceX宣布新一轮太空旅行计划,美国富豪成回头客...
  3. 二、MySql优化七个查询命令特征
  4. windows编程,服务器与客户端
  5. 获取顶级常量、祖先链、私有方法
  6. [Qt教程] 第15篇 2D绘图(五)绘制图片
  7. [蓝桥杯2016决赛]一步之遥-枚举
  8. qt 中使用openssl_openSSL漏洞致使SSL证书安全配置评级F
  9. JAVA 简单的抽奖程序
  10. 嵌入式开发有年龄限制吗_报名深圳成考有年龄限制吗?
  11. 使用wampserver部署的织梦站点无法登录后台
  12. LeetCode 第 69 场力扣双周赛
  13. Prototype使用$F()函数
  14. sql plus命令大全(2)
  15. 电脑硬件故障排除经验
  16. python电话簿_python 联系簿
  17. 2019念念不忘,2020必有回响!!!
  18. (原创)C# LRC复读机-1
  19. php共享汽车怎么扫码开车,共享汽车套路真多!看完恍然大悟
  20. 如何制作SSL证书即https服务支持

热门文章

  1. 布隆过滤器速度_详解布隆过滤器的原理、使用场景和注意事项
  2. 算法设计与分析:(二)动态规划
  3. java登录界面命令_Java命令行界面(第10部分):picocli
  4. spring 启动进度_在Web浏览器中显示Spring应用程序启动的进度
  5. 声明式编程与函数式编程_实用程序类与函数式编程无关
  6. 使用适用于Java 2的AWS开发工具包的AWS DynamoDB版本字段
  7. Java 8 Stream中间操作(方法)示例
  8. javafx_JavaFX技巧4:总结
  9. Selenium WebDriver中的TestNG侦听器及示例
  10. akka2.5_发布Akka Toolkit 2.3