JMM(Java内存模型)
JMM(Java内存模型)

JMM(Java内存模型)

Java内存模型(JMM)本身是一种抽象的概念,并不真实存在,它描述的是一组规则或规范,通过这组规则定义程序中各个变量的访问方式。JMM规定:所有变量存储在主内存中,是共享内存区域,所有线程可以访问,当线程想要堆一个变量进行操作时,必须在工作内存中进行。

JMM的关键在于解决多线程环境下,由于CPU缓存、处理器优化、指令重排序等底层原因导致的可见性、有序性和原子性问题,通过定义一些列的规则,屏蔽底层硬件和操作系统的内存访问差异,实现Java程序在各种平台都能达到一致的内存访问效果。

Java创建线程的方式:

  • 在类加载的时候,Java方法和JVM方法进行绑定;
  • 当调用Thread.start()方法时,Java层调用start0()方法,找到与之绑定的JVM层函数,这个函数调用create_thread()函数,创建原生的操作系统线程
  • 创建出一条内核线程后,映射Java线程与OS线程
  • 最后执行载入的线程体,也就是编写的run()方法
  • 操作系统内核将任务映射到各个处理器,这种轻量级进程(线程)与内核线程之间一对一的关系,就是Java线程与OS内核线程的一对一模型。

Java线程的执行,最终都会映射到硬件处理器上,但是对于硬件来说,只有寄存器、高速缓存、主存,并没有工作内存和主内存的区分,也就是JMM的划分无法对硬件的内存产生任何影响,不管是工作内存的数据还是主内存的数据,对于计算机硬件来说,都有可能存储在计算机主存、CPU高速缓存或者寄存器中。

原子性

一个操作是不可中断的,要么不做,要么必须全部做完,即使在多线程环境下。

现代操作系统采用基于时间片的抢占式调度,一个线程的执行时间用完后,操作系统会切换到另一个线程执行。

硬件:(1)总线锁定:当一个CPU需要对共享内存进行原子操作时,它会向总线发送一个LOCK信号,其他的读写请求都会被阻塞。(2)缓存锁定:在缓存行上进行锁定,其他CPU无法修改这个缓存行的数据。(3)原子指令:CAS等

软件:(1)synchronized关键字(2)实现lock接口(3)原子类

可见性

一个线程修改了共享变量的值,其他线程能够马上感知到。

当一个线程修改了变量,它首先修改的是自己缓存中的副本,然后在某个时间刷新回主内存,其他线程可能读取到旧值;编译器和处理器优化,如果一个变量被频繁读写,优化器可能决定只在寄存器中操作它,延迟写回主内存,这也会导致其他线程看不到新的值。

硬件:缓存一致性协议(监听总线上的读写事件,如果缓存行的数据失效,重新从内存加载)和内存屏障(强制刷新回主内存、强制失效本地缓存的数据,重新加载)

软件:volatile关键字、synchronized关键字、final关键字

有序性

程序的执行顺序按照代码的先后顺序执行。

在多线程环境下,重排后的指令与原指令顺序未必一致,

硬件:内存屏障(屏蔽的是屏障外的和屏障内的指令重排,内部和外部还是可以重排的)

软件:Happens-Before原则、volatile、synchronized关键字

Java程序中,在本线程内,所有操作都视为有序,如果是多线程环境下,一个线程中观察另一个线程,所有操作都是无序的。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注