Java内存模型

内存模型

在多CPU系统上,每个CPU都有多级缓存,一般分为L1,L2,L3,正是因为这些缓存的存在,提供了数据的访问性能(CPU的处理速度大于硬盘速度),也减轻了数据总数的传输压力,同时也带来了一些挑战,比如两个CPU同时访问一个内存地址,会发生什么?在什么条件下可以看到相同结果。这些都是需要去解决的。

在CPU层面,内存模型的定义是充分必要的,其他CPU的写入操作对当前CPU是可见的,当前CPU的写入操作对其他CPU也是可见的。

  • 保证这种可见性,有些处理器提供了强内存模型,所有CPU在任何时候都能看到CPU中任意位置相同的值,这种完全是硬件提供的支持。

  • 其他处理器,提供了弱内存模型,需要执行一些特殊的指令(如:memory barriers内存屏障),刷新CPU缓存到主存中,保证这个写入操作对其他线程可见。或者将CPU缓存的状态设置为无效(重新从主存中获取数据),保证其他CPU的写操作对本CPU可见。

Java内存模型

在Java内存模型中,描述了在多线程代码中,哪些行为是正确的,合法的。以及多线程之间线程通讯,代码中的变量如何反映的主存,CPU缓存中的底层细节。在学习之前,我们需要认识几个基础概念:内存屏障(memory Barriers),指令重排序,happens-before规则,as-if-serial语义。

内存屏障 Memory Barrier

内存屏障,又称内存栅栏,是一个CPU指令
1,保证特定操作的执行顺序
2,影响某些数据(或者是某条指令的执行结果)的内存可见性

编译器和CPU可以重排指令,保证最终的执行结果,尝试优化性能。插入一条Memory Barrier会告诉编译器和CPU,不管什么指令,都不能和这条Memory Barrier指令重排序。

Memery Barrier 所做的另外一件事是强刷出各种CPU cache,如一个Write-barrier(写入屏障)将刷出所有在Barrier之前写入cashe的数据,因此,任何CPU上的线程都能读取到这些数据的最新版本。

指令重排序
  1. 编译器优化重排序:编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
  2. 指令级并行的重排序:如果不存l在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
  3. 内存系统的重排序:处理器使用缓存和读写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。
happens-before规则

从jdk5开始,java使用新的JSR-133内存模型,基于happens-before的概念来阐述操作之间的内存可见性。

在JMM中,如果一个操作的执行结果需要对另一个操作可见,那么这两个操作之间必须要存在happens-before关系,这个的两个操作既可以在同一个线程,也可以在不同的两个线程中。

与程序员密切相关的happens-before规则如下:
1、程序顺序规则:一个线程中的每个操作,happens-before于该线程中任意的后续操作。
2、监视器锁规则:对一个锁的解锁操作,happens-before于随后对这个锁的加锁操作。
3、volatile域规则:对一个volatile域的写操作,happens-before于任意线程后续对这个volatile域的读。
4、传递性规则:如果 A happens-before B,且 B happens-before C,那么A happens-before C。

注意:两个操作之间具有happens-before关系,并不意味前一个操作必须要在后一个操作之前执行!仅仅要求前一个操作的执行结果,对于后一个操作是可见的,且前一个操作按顺序排在后一个操作之前。

数据依赖性

如果两个操作访问同一个变量,其中一个为写操作,此时这两个操作之间存在数据依赖性。
编译器和处理器不会改变存在数据依赖性关系的两个操作的执行顺序,即不会重排序。

as-if-serial语义

不管怎么重排序,单线程下的执行结果不能被改变,编译器、runtime和处理器都必须遵守as-if-serial语义。

相关关键字

在Java中包含几个关键字:volatile、final、synchronized关键字,帮助程序员把代码中的并发需求描述给编译器。Java内存模型中定义了他们的行为,确保正确同步的Java代码在所有处理器架构上能够正确执行。

synchronized

对于同一个monitor对象,只能被一个线程持有,这是synchronized关键字的互斥功能,synchronized还保证了在同步代码块期间,进行的写入操作对其他后续进入同步代码块的线程是可见的,同步代码始终在获取和释放monitor之间。在线程释放monitor时,会将缓存中的数据刷新到内存中。其他线程获取monitor时,使CPU缓存失效,从而使变量重新在主存中加载。

final

如果一个类包含final字段,且在构造函数中初始化,那么正确的构造一个对象后,final字段被设置后对于其它线程是可见的。

这里所说的正确构造对象,意思是在对象的构造过程中,不允许对该对象进行引用,不然的话,可能存在其它线程在对象还没构造完成时就对该对象进行访问,造成不必要的麻烦。

class FinalFieldExample {
  final int x;
  int y;
  static FinalFieldExample f;
  public FinalFieldExample() {
    x = 3;
    y = 4;
  }

  static void writer() {
    f = new FinalFieldExample();
  }

  static void reader() {
    if (f != null) {
      int i = f.x;
      int j = f.y;
    }
  }
}

这里可以保证其他线程看到的x=3,但不能保证y=4。

public FinalFieldExample() { // bad!
  x = 3;
  y = 4;
  // bad construction - allowing this to escape
  global.obj = this;
}
volatile

volatiile主要用于线程间通讯,volatile保证每次的读行为都在其他线程最后一次对该变量的写行为之后,每一次读取数据都是主存的值。另外,volatile会禁止写入指令的重排序。

双重锁

double-checked locking双重锁是一种延迟初始化的技巧,避免了同步开销。

private static Something instance = null;

public Something getInstance() {
  if (instance == null) {
    synchronized (this) {
      if (instance == null)
        instance = new Something();
    }
  }
  return instance;
}

虽然这种方法看起来很聪明,但是有可能不起作用。因为实例的初始化和实例字段的写入,可能被编译器重排序,这样就有可能返回还未构造的对象,结果就是读到一个初始化未完成的对象。这个问题可以使用volatile修复。

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值