学习Java内存模型JMM心得

 更新时间:2017年12月22日 09:15:59   作者:钟绍威  
这篇文章主要介绍了学习Java内存模型JMM的心得以及对其原理做了深入的介绍,有兴趣的朋友学习下吧。

有时候编译器、处理器的优化会导致runtime与我们设想的不一样,为此Java对编译器和处理器做了一些限制,JAVA内存模型(JMM)将这些抽象出来,这样编写代码时就无需考虑那么多底层细节,并保证“只要遵循JMM的规则编写程序,其运行结果一定是正确的”。

JMM的抽象结构

在Java中,所有的实例、静态变量存储在堆内存中,堆内存是可以在线程间共享的,这部分也称为共享变量。而局部变量、方法定义参数、异常处理参数是在栈中的,栈内存不在线程间共享。

而由于编译器、处理器的优化,会导致共享变量出现可见性问题,像在多核处理器中(multi-processor),线程可以在不同的处理器上执行,而处理器之间缓存不一致,会使共享变量出现可见性问题,有可能两个线程看到同一个变量不同值。

JMM将这些硬件做的优化抽象成每个线程都有一个本地内存。需要读写共享变量时,从主内存中拷贝一份到本地内存。当写共享变量时,先写到本地内存中去,在将来某个时间再刷新到主内存中。当再次读共享变量时,则只会从本地内存中读取。

这样线程间通讯就需要经过两步:

写线程:刷新本地内存到主内存中去读线程:从主内存读取更新后的值

这样在写-读之间就有一个延迟:本地内存什么时候刷新到主内存中去?导致可见性问题,不同线程可能看到的共享变量不一样。

happens-before

从字面上看happens-before的意思是“发生在此之前”。这是java对程序执行顺序制定的规则,实现同步必须遵循该规则。这样程序员只需要写出正确的同步程序,happens-before保证运行结果不会错。

A happens-before B,不仅仅表示A在B之前执行,还意味着A的执行结果对B可见,这保证了可见性。

A happens-before B,A也不一定要在B之前执行,如果AB交替,执行结果任然正确,则允许编译器、处理器进行优化重排序。所以只要程序结果正确,编译器、处理器怎么优化,怎么重排序都没问题,都是好的。

happens-before规则

程序顺序规则:在一个线程中,前面的操作happens-before后面的操作锁规则:对同一个锁,解锁happens-before加锁 volatile域规则:写volatile变量,happens-before后面任意一个读这个volatile变量的操作传递性:A happens-before B,B happens-before C,则A happens-before C start()规则:如果线程A执行ThreadB.start() 那么ThreadB.start() happens-before 线程B中任何操作 join()规则:如果线程A执行ThreadB.join(),那么线程B中的所有操作happens-before ThreadB.join()

下面这个示例有助于理解happens-before

double pi = 3.14; //A
double r = 1.0; //B
double area = pi * r *r; //C

这里有三个happens-before关系,规则1、2是程序顺序规则,规则3是传递性规则推导出来的:

A happens-before B B happens-before C A happens-before C

C依赖于A、B,但是A和B谁也不依赖。所以即使A和B重排序,执行结果也不会发生变化,这种重排序,JMM是运行的。

下面两种执行顺序的结果都是正确的。

以上就是我们给大家整理的关于Java内存模型JMM学习心得的全部内容,更多问题大家可以在下方留言讨论,感谢你对脚本之家的支持。

相关文章

  • Java如何获取Date的“昨天”与“明天”示例代码

    Java如何获取Date的“昨天”与“明天”示例代码

    最近在做项目的时候用到Date和Calendar比较多,而且用到的方式也比较全,突然想到一个问题,Java如何获取Date的"昨天"与"明天",也就是前一天和后一天呢?思考后写出了方法,想着万一以后用到,就总结出来,也方便有需要的朋友们参考借鉴,下面来一起看看吧。
    2016-12-12
  • Java 手写LRU缓存淘汰算法

    Java 手写LRU缓存淘汰算法

    本文主要讲了如何通过哈希链表这种数据结构来实现LRU算法,提供了三种实现思路,第一种从双向链表开始,借助于HashMap来实现满足要求的LRUCache
    2021-05-05
  • SpringBoot中的@RestControllerAdvice注解详解

    SpringBoot中的@RestControllerAdvice注解详解

    这篇文章主要介绍了SpringBoot中的@RestControllerAdvice注解详解,RestControllerAdvice注解用于创建全局异常处理类,用于捕获和处理整个应用程序中的异常,需要的朋友可以参考下
    2024-01-01
  • Java实现两人五子棋游戏(七) 屏幕提示信息

    Java实现两人五子棋游戏(七) 屏幕提示信息

    这篇文章主要为大家详细介绍了Java实现两人五子棋游戏,屏幕提示游戏信息,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03
  • java反射之Method的invoke方法实现教程详解

    java反射之Method的invoke方法实现教程详解

    这篇文章主要给大家介绍了关于java反射之Method的invoke方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • 解析Hibernate + MySQL中文乱码问题

    解析Hibernate + MySQL中文乱码问题

    如果持久化的类中有包括了汉字的String对象,那么对应到数据库中汉字的部分就会是乱码。这主要是由于MySQL数据表的字符集与我们当前使用的本地字符集不相同造成的
    2013-07-07
  • 详解Java中@Override的作用

    详解Java中@Override的作用

    这篇文章主要介绍了详解Java中@Override的作用的相关资料,希望通过本文能帮助到大家,让大家理解这部分内容,需要的朋友可以参考下
    2017-10-10
  • 详解Mybatis模板(已优化)适合小白

    详解Mybatis模板(已优化)适合小白

    这篇文章主要介绍了Mybatis模板(已优化)适合小白,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • Java listener简介_动力节点Java学院整理

    Java listener简介_动力节点Java学院整理

    这篇文章主要介绍了Java listener简介,可以用于统计用户在线人数等,有兴趣的可以了解一下
    2017-07-07
  • 以实例简介Java中线程池的工作特点

    以实例简介Java中线程池的工作特点

    这篇文章主要介绍了以实例简介Java中线程池的工作特点,线程池是Java实现多线程编程的基础,需要的朋友可以参考下
    2015-09-09

最新评论