前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM-13.Java内存模型

JVM-13.Java内存模型

作者头像
悠扬前奏
发布2019-05-28 13:21:12
3930
发布2019-05-28 13:21:12
举报

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
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.04.24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 主内存和工作内存
  • 2. 内存间相互操作
  • 3. volatile
  • 4. 原子性,可见性,有序性
  • 5. 先行发生原则
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档