Java 内存模型

并发编程的两个关键问题

  • 线程间如何通信?
  • 线程间如何同步?

有两种模型解决这两个问题。

  • 消息传递并发模型
  • 共享内存并发模型
通信同步
消息传递线程间没有公共状态,通过发送消息来显式通信。发送消息天然同步,因为发送消息总是在接收消息之前,同步是隐式的。
共享内存通过写-读内存中的公共状态来隐式通信。必须显式指定某段代码在线程间互斥执行,同步时显式的。

Java 使用的是共享内存并发模型

Java 内存模型抽象结构

运行时内存的划分

线程共享数据区线程私有数据区
方法区虚拟机栈
本地方法栈
程序计数器

对于每一个线程来说,栈是私有的,堆是共享的。

栈中变量(局部变量,方法定义参数,异常处理器参数)不在线程中共享,也就不会有内存可见性的问题,也不受内存模型的影响。

内存可见性针对的是共享变量

堆是共享的,为什么会有内存不可见的问题?

因为现代计算器为了高效,往往会在高速缓存区缓存共享变量,因为cpu访问缓存区比内存速度快的多。

线程间共享变量存在于主内存,每个线程都一个私有的本地内存,存储了共享变量的副本。

线程只能堆共享变量的副本进行读-写操作。

  • 共享变量都在主内存
  • 每个线程都保存了一份共享变量的副本
  • 如果线程A与线程B之间要通信,要经历下面的步骤
    • 线程A将本地内存A更新的副本刷新到主内存
    • 线程B从主内存读取线程A更新的共享变量

线程A无法直接访问线程B的本地内存

线程B并不是直接读取主内存的值,而是在本地内存B找到这个共享变量,发现已经被更新了,然后本地内存B去主内存读取最新的共享变量的值,并拷贝的本地内存B,然后线程B从本地内存B获取到值。

如何直到共享变量被其他线程更新了呢?

Java 内存模型( JMM )通过控制主内存与各线程本地内存的交互,来提供内存可见性保证。

Last Updated:
Contributors: himcs