本文介绍一下Java多线程中比较重要的部分——Java内存模型,也就是我们说的JMM。
很多人会把Java内存模型和Java内存区域弄混,Java内存区域又叫运行时数据区,我们之前在介绍Java虚拟机的文章中也已经讲过了,有兴趣的朋友可以翻一翻我之前的文章。但是这两个概念也并不是完全没有关系,我们先简单回顾一下Java内存区域的概念。Java内存区域主要分为线程共享的堆和方法区以及线程私有的程序计数器、虚拟机栈和本地方法栈。
下图展示了Java内存模型的结构。主内存是多个线程共享的区域,对应上面的Java内存区域中的堆区和方法区,本地内存为线程所私有,对应了Java内存区域的程序计数器、虚拟机栈和本地方法栈。当然,Java内存模型本质上只是抽象的概念。
上图的线程A和线程B都拥有各自的本地内存,本地内存相当于是每个线程将主存中的变量存在本地的一个副本。因为CPU的速度远远高于主存,因此本地内存的作用是缓解CPU与主存之间速度不匹配的矛盾。但本地内存也因此带来了一些问题,比如多个线程同时操作一个变量,实际上操作的都是本地内存中的变量而非主存中的,因此一个线程修改数据后另一个线程并不能感知到修改的数据,这就带来了线程安全问题。
因此,为线程提供内存的可见性保障就成了比较重要的问题。这里必须要提一下Java中的volatile
关键字,它的一个重要特征就是能够保证内存可见性。下面这个图演示了线程A和线程B通过volatile
进行线程通信的过程。
当线程A往本地内存中写入一个变量x=1
时,会同时将变量刷新到主存中去,当线程B在本地内存中获取x
的值时,会从主存中将x
同步到线程B的本地内存,然后读取本地内存。