JVM-13.Java内存模型

1. 主内存和工作内存

  • 所有变量和都存储在主内存(Main Memory)中
  • 每个线程有自己的工作内存(Working Memory)
    • 工作内存保存了该线程使用的变量的主内存副本拷贝
    • 线程对变量的所有操作都在工作内存中进行
    • 不同线程不能访问对方工作内存中的变量,线程间值传递通过主内存完成

2. 内存间相互操作

主内存到工作内存,工作同步回主内存,Java内存模型定义8种操作来完成,JVM保证8种操作都是原子的,不可再分的。

  • lock(锁定):作用于主内存变量,把一个变量标记为线程独占
  • unlock(解锁):作用于主内存变量,把一个处于锁定状态的变量释放出来,才能给其他线程锁定
  • read(读):作用于主内存变量,将变量值从主内存传输到工作内存,以供load动作使用
  • load(载入):作用于工作内存变量,将read操作从主内存得到的值放入工作内存的变量副本中
  • use(使用):作用于工作区内存变量,将工作内存中的一个值传递给执行引擎,当JVM遇到一个需要使用到变量的值的字节码指令时将执行这个操作
  • assign(赋值):作用于工作内存变量,把一个从执行引擎接收到的值赋值给工作内存的变量,当JVM遇到一个给变量赋值的字节码指令时执行这个操作。
  • store(存储):用于工作区内存,把工作区中的一个变量的值传送到主内存中,以便随后的write操作使用
  • write(写入):用于主内存变量,把store操作从工作内存中得到的变量值放到主内存的变量中。

8种操作的规则:

  • read和load,store和write不能单独出现
  • 线程assign之后必须同步回主内存
  • 线程不能无assign就把数据同步回主内存
  • 新变量只能在内存中产生
  • 同一变量统一时刻只能由一个线程进行lock操作,但是一个线程可以多次lock,之后同样次数的unlock才能解锁变量
  • lock操作会清空工作内存中这个变量的值,执行引擎使用这个值之前需要重新load或者assign操作初始化这个值
  • 变量没有lock不能unlock,也不能unlock被其他线程lock的变量
  • unlock之前必须先同步回主内存

3. volatile

  • 变量定义为volatile之后:
    • 所有线程可见:被线程修改的新值其他线程立即可知。普通线程的值需要传回主内存其他线程才知道。
    • 禁止指令重排优化通过在多个CPU访问同一块内存时添加内存屏障实现

4. 原子性,可见性,有序性

  • Java内存模型的8种操作保证原子性操作。synchronized块之间的操作也具备原子性
  • 可见性;
    • volatile提供多线程操作时变量的可见性
    • synchronized:synchronized块因为“对一个变量进行unlock之前一定要先同步回主内存”这条规则而可以提供可见性
    • final关键字也能提供可见性:被final修饰的字段在构造器中初始化完成后,且构造器没有吧this传递出去,在其他线程中就能看到final的值
  • 有序性:如果在本线程内观察,所有操作都是有序的(县城内串行语义);一个线程内观察另外一个线程,都是无序的(指令同步和主内存同步延迟)。
    • volatile关键之本身具有这个功能
    • synchronized关键字“一个变量在同一时刻只允许一条线成对其进行lock操作”,也就是说持有同一个锁的两个同步块只能串行进入

5. 先行发生原则

操作A先行发生于操作B的话,发生操作B之前,操作A产生的影响能被操作B观察到。 两个操作的关系不从以下规则推到出来的,没有顺序性保证,虚拟机可以对他们进行随意重排序:

  • 程序次序规则:一个线程内,代码写在前面的操作先行发生于写在后面的
  • 管程锁定规则:同一个锁,一个unlock操作先行发生于后面对同一个锁的lock操作
  • volatile变量规则,volatile变量的写操作先行发生于后面对这个变量的读操作
  • 线程启动规则:Thread对象的start()方法先行发生于该线程的任何操作
  • 线程中止规则:线程中所有操作先行发生于对此线程的中止检测,Thread.join()方法结束,Thread.isAlive()的返回值等手段检测到线程是否已经中止运行
  • 线程中断规则,线程interrupt()方法的调用先行发生于被中断线程检测到中断事情的发生。通过Thread.interrupted()方法检测到是否有中断发生
  • 对象终结原则:一个对象的初始化完成先行发生于finalize()方法的开始
  • 传递性:操作A先行与操作B,操作B先行于操作C,则A先行于C

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏腾讯音视频实验室

从HEVC到VVC:变换技术的演进(1)—— 主变换(Primary transform)

在视频编码标准过去三十多年的发展历程中,离散余弦变换(Discrete Cosine Transform,DCT)Type 2 (后面简称为DCT2)因其较低的...

43560
来自专栏Python数据科学

优雅你的Python代码的15个tips

前言:师妹前段时间非常认真地选了下学期的《大数据分析实践》选修课,根据几位师兄的建议买了本书开始自学 Python 语言。然而年后再见,师妹说她看完了书,做了一...

9820
来自专栏微信公众号:Java团长

【面试被虐】游戏中的敏感词过滤是如何实现的?

小秋今天去面试了,面试官问了一个与敏感词过滤算法相关的问题,然而小秋对敏感词过滤算法一点也没听说过。于是,有了以下事情的发生…..

21360
来自专栏腾讯音视频实验室

从HEVC到VVC:变换技术的演进(2)—— 二次变换(Secondary transform)

当前主流的视频编码标准(例如MPEG-2,H.264,VP9,AVS1等)均采用行列可分离的主变化(Separable primary transform)技术...

55130
来自专栏ATYUN订阅号

从浅到深全面理解梯度下降:原理,类型与优势

梯度下降是迄今为止最流行的优化策略,用于机器学习和深度学习。它在训练模型时使用,可以与每个算法结合使用,易于理解和实现。

15640
来自专栏mwangblog

Dijkstra算法

Dijkstra算法使用了广度优先搜索解决赋权有向图(或无向图)的单源最短路径问题。

31530
来自专栏大数据文摘

Github标星1k+,懂点Python就能读懂的机器学习全流程笔记

学完Python基础,研究机器学习,听说只需要调用scikit-learn库就可以了?

11740
来自专栏Fundebug

8 个 Tips 让你更好的进行 Code Review

你在学校里不曾学到的东西中有一件是:如何才做出优秀的 Code Review。你学到了算法、数据结构、编程语言基础知识,但没有人坐下来说:“下面介绍如何确保你如...

11660
来自专栏大数据文摘

人工智能落地之路:从概念验证到产品

只有不到20%的机器学习PoC(概念验证)项目能够顺利投产,而这其中的大部分也可能会止步于其方案的“产品化”阶段。从概念验证到实际产品,人工智能应用落地到底要跨...

13740
来自专栏鸿的学习笔记

Presto对ORC格式的优化

最近Presto的官网发表了一篇文章,叙述了新版本的Presto对ORC格式读取的性能优化过程,包含了很多代码细节,非常有趣,故进行简单编译。

35040

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励