Java内存模型把Java虚拟机内部划分为线程栈和堆。每个线程都有自己的线程栈。如下图。
线程栈(Thread Stack):线程栈中存放了本地变量(线程执行过程中在方法内定义的变量,无论是基本类型还是引用类型)堆(Heap):堆上则存放Java程序中创建的所有对象,一个对象包含的成员变量跟随对象一起存放在堆上
在多核CPU中,在同一时刻,可能每个CPU上边都同时分别跑着一个线程。
对于理解Java内存模型和内存交互原理,只需要知道CPU内部有一个缓存即可。如下图。
硬件内存架构没有区分线程栈和堆。对于硬件,所有的线程栈和堆都分布在主内中。部分线程栈和堆可能有时候会出现在CPU缓存中和CPU内部的寄存器中。如下图。
当对象和变量被存放在计算机中各种不同的内存区域中时,就可能会出现一些具体的问题。主要包括如下两个方面:
线程对共享变量修改的可见性当读,写和检查共享变量时出现竞争条件(race conditions)对于共享对象,多个CPU上的线程可以同时将其读到CPU缓存中,然后修改这个对象。只要CPU缓存没有被刷新会主存,对象修改后的版本对跑在其它CPU上的线程都是不可见的。这种方式可能导致每个线程拥有这个共享对象的私有拷贝,每个拷贝停留在不同的CPU缓存中。如下图。 从本质上来讲,这是CPU的自身速度优化,使最新的Java对象不能及时地在多个线程相互可见(一个特性的优化往往会对另一个特性造成缺口)
如果两个线程同时将整型变量count读到各自的CPU缓存中,并且同时对其执行+1操作,最后再将count写会到内存中,最终count的值只会被+1,而不是+2,尽管执行了两次+1操作。
原文链接
新闻热点
疑难解答