java并发编程的艺术(三)-----java内存模型

来源:互联网 发布:淘宝账号贷款怎么操作 编辑:程序博客网 时间:2024/06/05 14:08

前言

要想对java内存模型有深入的了解,就必须得了解里面涉及到的顺序一致性内存模型、重排序以及happen-before

顺序一致性模型

顺序一致性模型是计算机科学家们提出的一个理想的参考模型,并不是Java运用的模型!再次强调,是一个理想的理论模型!!Java内存模型也需参考顺序一致性模型进行实现,过程中就需要涉及到重排序和happens-before。
顺序一致性内存模型有两大特性来保证为程序猿提供极强(是极强)的内存可见性

  • 一个线程的所有操作都必须按照程序写的顺序来执行
  • 所有线程都只能看见一种单一的执行顺序

为什么不按照顺序一致性模型强设计java内存模型

如果完全按照顺序一致性模型来设计,我们的JMM需要对禁止大量的处理器和编译器的优化,这将导致程序的执行性能严重下降。

Java内存模型

在线程与线程之间,java采用了共享内存的方式来通信,而不是消息传递。Java线程之间的通信由Java内存模型进行控制(简称JMM),每个线程都有属于自己的本地内存,里面存放的是该线程对读/写共享变量的副本,而真正的共享变量是存放在主内存中的。
PS:共享变量可以大致理解为JVM在运行时的堆内存里面的数据,因为这里面的数据是线程共享的,而栈里面的数据不属于共享变量因为它是线程私有的。
(此处有图片,待续)
线程与线程之间在通信的时候,无外乎就是将写的共享变量要刷新到主内存,而其他线程要读的时候必须从主内存中去读,这样就可以为程序猿提供了内存可见性保证。

重排序

JMM为了程序在执行代码的时候性能更好,支持处理器和编译器对指令进行重排序,包括编译器优化重排序、指令级优化重排序以及内存系统重排序。
- 编译期优化重排序——不改变单线程语义的情况下改变语句的执行顺序
- 指令级优化重排序——对不存在数据依赖的代码语句在处理器中改变指令的指令的执行顺序。
- 系统内存优化重排序——系统内存对加载和存储顺序不一致

为了避免在重排序时造成存在数据依赖性的语句被重排序了导致程序结果与正确结果不一致的情况,故而引出了happens-before以及用内存屏障实现happens-before

happens-before

定义

如果一个操作的执行结果需要对另一个操作可见,那么这两个操作之间必须拥有happens-before关系

happens-before规则

  • 程序顺序规则:线程中的每一个操作happens-before后续的线程操作
  • 监视器规则:对锁的释放happens-before对锁的获取
  • 传递性
  • start()规则:执行线程的start方法要happens-before该线程里面的任意操作
  • join()规则:执行ThreadB.join,则执行B线程里面的方法要happens-before  join方法返回
    根据第一个程序顺序规则,我们可以知道JMM并不强制要求按照happens-before的先后顺序结果执行,只要执行结果不变就行(JSR-133对happens-before关系的定义)

内存屏障

为了严格限制编译期和处理器对某些语句不能进行重排序,JMM会在编译器生成字节码文件的时,在指令序列中内存屏障来禁止摸顶类型的处理器重排序。

阅读全文
0 0