Java内存模型(一)

[TOC]

1.内存模型的定义

Java 内存模型试图来屏蔽掉各种硬件和操作系统的内存访问差异,让Java程序在各种平台上都能达到一致的内存访问效果。简单来说,由于CPU执行指令的速度是很快的,但是内存访问的速度就慢了很多,相差的不是一个数量级,又在CPU里加了好几层高速缓存。

在Java内存模型里,对上述的优化又进行了一些抽象。JMM规定所有变量都是存在主存中的,每个线程又包含自己的工作内存,也就是CPU上的寄存器或者高速缓存。所以线程的操作都只能访问自己的工作内存,且工作前后都要把值在同步回主内存。

read:把一个变量的值从主内存传输到工作内存中
load:在 read 之后执行,把 read 得到的值放入工作内存的变量副本中
use:把工作内存中一个变量的值传递给执行引擎
assign:把一个从执行引擎接收到的值赋给工作内存的变量
store:把工作内存的一个变量的值传送到主内存中
write:在 store 之后执行,把 store 得到的值放入主内存的变量中
lock:作用于主内存的变量
unlock

3.内存模型三大特性

1.原子性:

一个或多个操作,要么全部执行且在执行过程中不被任何因素打断,要么全部不执行。

Java 内存模型保证了 read、load、use、assign、store、write、lock 和 unlock 操作具有原子性,例如对一个 int
类型的变量执行 assign 赋值操作,这个操作就是原子性的。但是 Java 内存模型允许虚拟机将没有被 volatile 修饰的
64 位数据(long,double)的读写操作划分为两次 32 位的操作来进行,即 load、store、read 和 write 操作可以
不具备原子性。

2.可见性

可见性指当一个线程修改了共享变量的值,其它线程能够立即得知这个修改。Java 内存模型是通过在变量修改后将新
值同步回主内存,在变量读取前从主内存刷新变量值来实现可见性的。

主要有三种实现可见性的方式:

  • volatile
  • synchronized,对一个变量执行 unlock 操作之前,必须把变量值同步回主内存。
  • final,被 final 关键字修饰的字段在构造器中一旦初始化完成,并且没有发生 this 逃逸(其它线程通过 this 引
    用访问到初始化了一半的对象),那么其它线程就能看见 final 字段的值。

3.有序性

有序性是指:在本线程内观察,所有操作都是有序的。在一个线程观察另一个线程,所有操作都是无序的,无序是因
为发生了指令重排序。在 Java 内存模型中,允许编译器和处理器对指令进行重排序,重排序过程不会影响到单线程
程序的执行,却会影响到多线程并发执行的正确性。
volatile 关键字通过添加内存屏障的方式来禁止指令重排,即重排序时不能把后面的指令放到内存屏障之前。