在
Java
中,所有
实
例域、静
态
域和数
组
元素都存
储
在堆内存中,堆内存在
线
程之
间
共享
(本章用
“
共享
变
量
”
这
个
术语
代指
实
例域,静
态
域和数
组
元素)。局部
变
量(
Local Variables
),方
法定
义
参数(
Java
语
言
规
范称之
为
Formal Method Parameters
)和异常
处
理器参数(
Exception
Handler Parameters
)不会在
线
程之
间
共享,它
们
不会有内存可
见
性
问题
,也不受内存模型的影
响。
Java
线
程之
间
的通信由
Java
内存模型(本文
简
称
为
JMM
)控制,
JMM
决定一个
线
程
对
共享
变
量的写入何
时对
另一个
线
程可
见
。从抽象的角度来看,
JMM
定
义
了
线
程和主内存之
间
的抽
象关系:
线
程之
间
的共享
变
量存
储
在主内存(
Main Memory
)中,每个
线
程都有一个私有的本地
内存(
Local Memory
),本地内存中存
储
了
该线
程以
读
/
写共享
变
量的副本。本地内存是
JMM
的
一个抽象概念,并不真
实
存在。它涵盖了
缓
存、写
缓
冲区、寄存器以及其他的硬件和
编译
器
优
化。
Java
内存模型的抽象示意如
图
3-1
所示。

从
图
3-1
来看,如果
线
程
A
与
线
程
B
之
间
要通信的
话
,必
须
要
经历
下面
2
个步
骤
。
1
)
线
程
A
把本地内存
A
中更新
过
的共享
变
量刷新到主内存中去。
2
)
线
程
B
到主内存中去
读
取
线
程
A
之前已更新
过
的共享
变
量。
下面通
过
示意
图
(
见图
3-2
)来
说
明
这
两个步
骤
。

如
图
3-2
所示,本地内存
A
和本地内存
B
由主内存中共享
变
量
x
的副本。假
设
初始
时
,
这
3
个
内存中的
x
值
都
为
0
。
线
程
A
在
执
行
时
,把更新后的
x
值
(假
设值为
1
)
临时
存放在自己的本地内存
A
中。当
线
程
A
和
线
程
B
需要通信
时
,
线
程
A
首先会把自己本地内存中修改后的
x
值
刷新到主内
存中,此
时
主内存中的
x
值变为
了
1
。随后,
线
程
B
到主内存中去
读
取
线
程
A
更新后的
x
值
,此
时
线
程
B
的本地内存的
x
值
也
变为
了
1
。
从整体来看,
这
两个步
骤实质
上是
线
程
A
在向
线
程
B
发
送消息,而且
这
个通信
过
程必
须
要
经过
主内存。
JMM
通
过
控制主内存与每个
线
程的本地内存之
间
的交互,来
为
Java
程序
员
提供
内存可
见
性保
证
。