java八股文面试[多线程]——主内存和工作内存的关系

这篇具有很好参考价值的文章主要介绍了java八股文面试[多线程]——主内存和工作内存的关系。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

java八股文面试[多线程]——主内存和工作内存的关系,java八股文,面试,职场和发展

JAVA内存模型(JMM)
共享变量:如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量。
上面的工作内存其实是java内存模型抽象出来的概念,下面简要介绍一下java内存模型(JMM)。
java内存模型(java memory model): 描述了java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取出变量这样的底层细节。

不同的平台,内存模型是不一样的,我们可以把内存模型理解为在特定操作协议下,对特定的内存高速缓存进行读写访问的过程抽象。Java 虚拟机规范中试图定义一种 Java 内存模型(Java Memory Model,简称 JMM)屏蔽掉各种硬件和操作系统的内存访问差异,以实现让 Java 程序在各种平台下都能达到一致的内存访问效果,不必因为不同平台上的物理机的内存模型的差异,对各平台定制化开发程序。
更具体一点说,Java 内存模型提出目标在于,定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。

java八股文面试[多线程]——主内存和工作内存的关系,java八股文,面试,职场和发展

 

从上图可以得出结论:

  • 所有的变量都存储在主内存
  • 每个线程都有自己独立的工作内存,里面保存该线程使用到的变量的副本(主内存该变量的一份拷贝)。

JMM关于synchronized的两条规定:

  1. 线程解锁前,必须把共享变量的最新值刷新到主内存中
  2. 线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值。(加锁和解锁需要是同一把锁)

线程解锁前对共享变量的修改在下次加锁前对其他线程可见。

JVM主内存与工作内存描述

JVM将内存为主内存工作内存两个部分。

主内存: 主要包括本地方法区和 

  • Java 内存模型规定了所有变量都存储在主内存(Main Memory)中(此处的主内存与介绍物理硬件的主内存名字一样,两者可以互相类比,但此处仅是虚拟机内存的一部分)。

工作内存: 每个线程都有一个工作内存,工作内存中主要包括两个部分,一个是属于该线程私有的和 对主存部分变量拷贝的寄存器(包括程序计数器PC和cup工作的高速缓存区)。

  • 每个线程都有自己的工作内存(Working Memory,又称本地内存.),线程的工作内存中保存了该线程使用到的变量,该变量是主内存中的共享变量的副本拷贝
  • (工作内存是 JMM 的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。)

java八股文面试[多线程]——主内存和工作内存的关系,java八股文,面试,职场和发展

 线程执行的时候,将首先从主内存读值,再load到工作内存中的副本中,然后传给处理器执行,执行完毕后再给工作内存中的副本赋值,随后工作内存再把值传回给主存,主存中的值才更新。
在这个过程中如果出现多个线程同时在处理这些值,岂不是会出现并发问题

java八股文面试[多线程]——主内存和工作内存的关系,java八股文,面试,职场和发展

1、所有的变量都存储在主内存中(虚拟机内存的一部分),对于所有线程都是共享的
2、每个线程都有自己的工作内存,工作内存中保存的是主存中某些变量的值的副本拷贝,线程对变量的所有操作都必须在工作内存中进行,不能直接读写主内存中的变量。
3、线程之间无法直接访问对方的工作内存中的变量值的,线程间变量的传递均需要通过主内存来完成。
这种划分与Java运行时内存区域中堆、栈、元空间等的划分是不同层次的划分,两者基本没有关系。硬要联系的话,大致上主内存对应Java堆中对象的实例数据部分、工作内存对应栈的部分区域;从更低层次上说,主内存对应物理硬件内存、工作内存对应寄存器和高速缓存

JVM内存间交互规则

关于主内存与工作内存之间的具体交互协议,即一个变量如何从主内存拷贝到工作内存、如何从工作内存同步回主内存之类的实现细节,Java 内存模型中定义了下面 8 种操作来完成。
java八股文面试[多线程]——主内存和工作内存的关系,java八股文,面试,职场和发展

  1. Lock(锁定):作用于主内存中的变量,把一个变量标识为被一个线程独占的状态。
  2. Unlock(解锁):作用于主内存中的变量, 将一个变量从锁定状态(Lock)释放出来,释放后的变量才可以被其他线程锁定(Lock)
  3. Read(读取):作用于主内存中的变量,将一个变量的值从主内存传输到工作内存中,以便随后的load操作使用
  4. Load(加载):作用于工作内存中的变量,把read操作从主内存中得到的变量的值放入工作内存的变量副本中。
  5. Use(使用):作用于工作内存中的变量,把工作内存中一个变量的值传递给执行引擎。(每当虚拟机遇到一个需要使用到变量的值的字节码指令时就会执行这个操作。)
  6. Assign(赋值):作用于工作内存中的变量,把一个从执行引擎接收到的值赋值给工作内存中的变量。(每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。)
  7. Store(存储):作用于工作内存中的变量,把工作内存中的一个变量的值传送到主内存中,以便随后 write 操作使用。
  8. Write(写入):作用于主内存中的变量,把store操作从工作内存中得到的变量的值放入主内存的变量中。

需知:

  • 在将变量从主内存读取到工作内存中,必须顺序执行read(读取)、load(加载)
  • 要将变量从工作内存同步回主内存中,必须顺序执行store(存储)、write(写入)

这8种操作必须遵循以下规则:

  1. 不允许read(读取)和load(加载)、store(存储)和write(写入)操作之一单独出现。即不允许一个变量从主内存被读取了,但是工作内存不接受,或者从工作内存回写了但是主内存不接受。

    不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步会主内存中

  2. 不允许一个线程丢弃它最近的一个assign(赋值)操作,即变量在工作内存被更改后必须同步改更改回主内存。即:执行store(存储),write(写入)操作

  3. 工作内存中的变量在没有执行过assign(赋值)操作时,不允许无意义的同步回主内存。 即:执行store(存储),write(写入)操作

  4. 在执行use(使用)前必须已执行load(加载),在执行store(存储)前必须已执行assign(赋值)

  5. 一个变量在同一时刻只允许一个线程对其执行lock操作,一个线程可以对同一个变量重复执行多次lock,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。lock和unlock必须成对出现。

  6. 一个线程在lock一个变量的时候,将会清空工作内存中的此变量的值,执行引擎在use(使用)前必须重新read(读取)和load(加载)初始化变量的值。

  7. 在执行unlock之前,必须首先执行了store(存储)和write(写入)操作

    对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)

  8. 线程不允许unlock其他线程lock操作。并且unlock操作必须是在本线程的lock操作之后。

    如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量。

从上面可以看出,把变量从主内存复制到工作内存需要顺序执行read、load,从工作内存同步回主内存则需要顺序执行store、write。总结:

  • read、load、use必须成对顺序出现,但不要求连续出现。assign、store、write同之;
  • 变量诞生和初始化:变量只能从主内存“诞生”,且须先初始化后才能使用,即在use/store前须先load/assign;
  • lock一个变量后会清空工作内存中该变量的值,使用前须先初始化;unlock前须将变量同步回主内存;
  • 一个变量同一时刻只能被一线程lock,lock几次就须unlock几次;未被lock的变量不允许被执行unlock,一个线程不能去unlock其他线程lock的变量。

JVM先行发生原则

Java内存模型具备一些先天的“有序性”,即不需要通过任何同步手段(volatile、synchronized等)就能够得到保证的有序性,这个通常也称为happens-before原则

 

知识来源:

【23版面试突击】你知道主内存和工作内存的关系?_哔哩哔哩_bilibili

【Java多线程】内存模型JMM—主内存与工作内存分析_主内存和工作内存_Archie_java的博客-CSDN博客文章来源地址https://www.toymoban.com/news/detail-683910.html

到了这里,关于java八股文面试[多线程]——主内存和工作内存的关系的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java八股文面试[多线程]——synchronized锁升级过程

    速记:偏向-轻量-重量 上面讲到锁有四种状态,并且会因实际情况进行膨胀升级,其膨胀方向是: 无锁——偏向锁——轻量级锁——重量级锁 ,并且膨胀方向 不可逆 一.锁升级理论. 在synchronized锁升级过程中涉及到以下几种锁.先说一下这几种锁是什么意思. 偏向锁: 只有一个

    2024年02月10日
    浏览(43)
  • java八股文面试[多线程]——synchronized锁升级详细流程

    偏向锁是JDK6中的重要引进,因为HotSpot作者经过研究实践发现,在大多数情况下,锁不仅不存在多线程竞争,而且总是由 同一线程多次获得 ,为了让线程获得锁的代价更低,引进了偏向锁。 偏向锁是在 单线程 执行代码块时使用的机制,如果在多线程并发的环境下(即线程

    2024年02月10日
    浏览(33)
  • java八股文面试[多线程]——Synchronized的底层实现原理

    笔试:画出Synchronized 线程状态流转 实现原理图 synchronized解决的是多个线程之间访问资源的同步性,synchronized 翻译为中文的意思是 同步 ,也称之为”同步锁“。 synchronized的作用是保证在 同一时刻 , 被修饰的代码块或方法只会有一个线程执行,以达到保证并发安全的

    2024年02月10日
    浏览(48)
  • java八股文面试[多线程]——并发三大特性 原子 可见 顺序

        AutomicInteger :  volatile + CAS 总线LOCK  MESI 两个协议 TODO volatile的可见性和禁止重排序是怎么实现的: DCL场景:  new操作会在字节码层面生成两个步骤: 分配内存、调用构造器 然后把引用赋值给singleton 不加volatile则会发生指令重排,可能得到不完整的对象 知识来源: 【并

    2024年02月11日
    浏览(53)
  • java八股文面试[多线程]——两个线程交替打印1-100之间的数字

    一份代码,两个线程,使用synchronize实现: 重写run()方法,将输出1到100之间整数的代码写到同步方法里。 线程1进入到同步方法,输出一个整数后,阻塞并释放锁。 线程2进入到同步方法,唤醒线程1,输出整数后,阻塞并释放锁。 线程1和线程2重复第3步,直到输出所有的整数

    2024年02月11日
    浏览(45)
  • java八股文面试[多线程]——ThreadLocal底层原理和使用场景

    源码分析: ThreadLocal中定义了ThreadLocalMap静态内部类,该内部类中又定义了Entry内部类。 ThreadLocalMap定了 Entry数组。 Set方法: Get方法: Thread中定义了两个ThreaLocalMap成员变量: Spring使用ThreadLocal解决线程安全问题  我们知道在一般情况下,只有 无状态的Bean 才可以在多线程环

    2024年02月10日
    浏览(52)
  • java八股文面试[多线程]——为什么要用线程池、线程池参数

     速记7个: 核心、最大 存活2 队列 工厂 拒绝 线程池处理流程: 线程池底层工作原理: 线程复用原理:   知识来源: 【并发与线程】为什么使用线程池,参数解释_哔哩哔哩_bilibili 【并发与线程】线程池处理流程_哔哩哔哩_bilibili 【并发与线程】线程池的底层工作原理_哔哩

    2024年02月11日
    浏览(51)
  • java八股文面试[多线程]——sleep wait join yield

          sleep和wait有什么区别 sleep 方法和 wait 方法都是用来将线程进入 阻塞状态 的,并且 sleep 和 wait 方法都可以响应 interrupt 中断,也就是线程在休眠的过程中,如果收到中断信号,都可以进行响应并中断,且都可以抛出 InterruptedException 异常,那 sleep 和 wait 有什么区别呢?

    2024年02月11日
    浏览(45)
  • 【面试系列】八股文之线程篇202306

    union all :包含重复行 union :不包含重复行 shutdown() ,调用shutdown方法,线程池会拒绝接收新的任务,处理中的任务和阻塞队列中的任务会继续处理。 shutdownNow() ,会给workers中所有的线程发送 interrupt 信号,将延迟队列的任务移除并返回。 原理分析 执行任务,尝试添加线程。

    2024年02月12日
    浏览(46)
  • 【面试八股文】每日一题:谈谈你对线程的理解

    每日一题-Java核心-谈谈你对线程的理解【面试八股文】   Java线程是Java程序中的执行单元。一个Java程序可以同时运行多个线程,每个线程可以独立执行不同的任务。线程的执行是并发的,即多个线程可以同时执行。   Java中的线程有如下的特点 轻量级:线程的创建和销毁

    2024年02月12日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包