理解Java内存模型
Java Memory Model(Java内存模型,简称JMM),作为Java语言规范的一部分(主要在JLS的第17章节介绍),其定义了多线程之间如何通过内存进行交互,在旧的JMM中,存在一些不够明确和过于限制的问题,比如对final,volatile等关键字的语义约束问题,例如,有可能出现final字段的值会发生变化,或者阻止编译器的优化操作,还有比较熟知的double-checked问题,于是在新的JMM中,针对这一系列问题作出了修订,最终在JSR133中进行了详细描述,本文将对Java内存模型作一番理解。
什么是Java内存模型(Java Memory Model)
在多核系统中,处理器通常会有一层或多层缓存,通过这些缓存可以加快数据访问(缓存数据距处理器更近)和降低共享内存总线上的通讯(因为本地缓存能够满足大多数内存操作)来提高CPU性能。缓存能够大大提升性能,但这同时也带来了许多挑战。例如,当两个CPU同时检查相同的内存地址时会发生什么?在什么样的条件下它们会看到相同的值?
在处理器层面上,JMM定义了一个充要条件: 让当前的处理器可以看到其他处理器写入到内存的数据以及其他处理器可以看到当前处理器写入到内存的数据。有些处理器具有强一致性内存模型,能够让所有的处理器在任何时候任何指定的内存地址上都可以看到完全相同的值。而另外一些处理器则具有弱一致性内存模型,在这种处理器中,必须使用内存屏障(一种特殊的硬件级别指令)来刷新本地处理器缓存并使本地处理器缓存无效,目的是为了让当前处理器能够看到其他处理器的写操作或者让其他处理器能看到当前处理器的写操作。这些内存屏障通常在机器指令中的lock和unlock操作的时候完成。内存屏障在高级语言中对程序员是不可见的。
JMM描述了在多线程中哪些行为是合法的,以及线程间如何通过内存进行交互。它描述了程序中的变量和从内存或者寄存器加载或存储它们的底层细节之间的关系,并通过使用各种硬件和编译器的优化(如重排序,高速缓存,机器指令交错执行等)来正确实现以上事情,比如从Java语言层面上,我们可以通过volatile, final以及synchronized关键字,Happens-Before关系等保证同步的java程序在所有的处理器架构下面都能正确的运行。
JMM规定了JVM必须遵循一组最小保证,这组保证规定了对变量的写入操作在何时将对于其他线程可见。JMM在设计时就在可预测性和程序的易于开发性之间进行了权衡,从而在各种主流的处理器体系架构上能实现高性能的JMM。