java内存模型介绍[通俗易懂]

java内存模型介绍[通俗易懂]####Java内存模型Java内存模型描述了Java虚拟机和计算机内存之间是如何协同工作的。一个Java虚拟机也是一个完整的计算机的模型,因此,这个模型自然也包含了内存模型。如果你想写出表现良好的并发程序就必须理解Java内存模型。Java内存模型描述了不同线程间如何和何时看到被其他线程修改的共享变量以及在需要时如何同步访问共享变量。原来的Java内存模型存在很多不足,所以在Java5时进行了修改。这个一直使用至今。####Java内存模型每个运行在Java虚拟机中的线程都拥有自己的线程栈。这

大家好,又见面了,我是你们的朋友全栈君。

####Java内存模型
Java内存模型描述了Java虚拟机和计算机内存之间是如何协同工作的。一个Java虚拟机也是一个完整的计算机的模型,因此,这个模型自然也包含了内存模型。

如果你想写出表现良好的并发程序就必须理解Java内存模型。Java内存模型描述了不同线程间如何和何时看到被其他线程修改的共享变量以及在需要时如何同步访问共享变量。

原来的Java内存模型存在很多不足,所以在Java5时进行了修改。这个一直使用至今。

####Java内存模型

Java_Memory_Model

每个运行在Java虚拟机中的线程都拥有自己的线程栈。这个线程栈包含了这个线程所调用方法的当前执行点,所有我们也可以称之为”调用栈“。在线程执行代码的过程总,调用栈随之发生变化。

线程栈也包含每个被执行的方法中的所有局部变量。一个线程只能访问自己的线程栈。一个线程创建的局部变量对其他线程是不可见的。即使两个线程执行同样的代码,这两个线程任然需要在它们各自的线程栈中创建这些变量。

所有的基本类型的局部变量都全部存放在各自的线程栈中,对其他线程不可见。一个线程可能会向另一个线程传递一个基本类型变量的拷贝,但是这并不能共享基本类型变量自身。

在堆中包含所有你在Java程序中创建的对象。这也包含所有基本类型所对应的装箱类型。即便,我们创建了一个对象然后我们把它赋给了一个局部变量,或者作为另一个对象的成员变量,这个对象仍然存放在堆中。

Java_Memory_Model

一个局部变量可能是基本类型,这样它就永远呆在线程栈中。

一个局部变量也可能是引用变量。在这种情况下,引用变量存放在线程栈中,对象本身存放在堆中。

一个对象可能包含方法,这些方法又可能包含局部变量。这些局部变量也被存放在线程栈中,即便这个方法所属的对象存放在堆中。

一个对象的成员变量随着对象自身存放在堆中。不管这个变量是基本类型还是引用类型都是如此。

静态类变量随着类定义也存放在堆中。

存放在堆中的对象可以被所有的线程通过指向对象的引用访问。当一个线程访问一个对象时,它也可以访问这个对象的成员遍历。如果两个线程在同一时刻调用同一个对象上的同一个方法,它们都可以访问对象的成员变量,但是每个线程都会拥有各自的局部变量拷贝。

Java_Memory_Model

####硬件内存架构
现代硬件内存架构和Java内存模型有一些不一样的地方。理解硬件内存架构和Java内存模型如何和它协同工作也非常重要。
通用的硬件内存架构:

hardware_memory_arch

现代计算机通常拥有两个或多个CPU。这些CPU中可能还有是多核的。这一点,使得多个线程同时运行在一台计算机上称为了可能。每个CPU可以在任何时刻运行一个线程。
这就意味着如果你的程序是多线程的,在你的程序内部,一个线程对应一个CPU可能同时运行。

每个CPU包含一些寄存器。CPU可以在这些寄存器上执行操作会比在内存上快很多。这是因为CPU访问寄存器的速度远高于访问内存的速度。

每个CPU还可能拥有一个CPU缓存层。实际上,现代计算机都会有一个一定大小的缓存层。CPU访问缓存的速度远高于主存,但通常又低于访问寄存器的速度。因此,缓存是用来平衡CPU访问寄存器和主存之间的速度差异的。一些CPU可能拥有多级缓存(一级缓存和二级缓存)。

一台计算机还拥有一块主存区域(RAM)。所有的CPU都可以访问主存。主存区域通常要比CPU的缓存大得多。

通常,当一个CPU需要访问主存的时候,它会将数据从主存读到CPU的缓存中,甚至再从CPU的缓存读到它内部的寄存器中,然后执行相关的操作。当CPU需要将结果写回到主存中时,它会先将值刷新到缓存中,然后在某一时刻刷新回主存中。

当CPU需要在缓存中存储一些其他的东西时,会将存储在缓存中的值刷新回主存中。

CPU缓存可以局部刷新。

####Java内存模型和硬件内存架构之间的联接

正如上面所提到的,Java内存模型和硬件内存架构是不同。在硬件内存架构并不区分内存栈和堆。在硬件中,所有的线程栈和堆都位于主存中。线程栈的一部分和堆可能同一位于CPU缓存和寄存器中。

gap

当对象和变量存放在计算机的不同内存区域中时,就会暴露出一些问题。主要包括两个方面:

  • 内存可见性
  • 当读,检查和写共享变量时的竞争条件

#####内存可见性
如果两个或多个线程共享同一个对象时,在不使用vloatile声明或者同步的情况下,一个线程更新了这个共享对象的值可能对其他线程不可见。

想象一下,这个共享对象最初存放在主存中。运行在一个CPU上的一个线程,将这个共享对象读到它的CPU缓存中。并在缓存中修改了这个共享对象。只要这个CPU缓存还没有刷新回主存,这个共享共享对象变化后的版本对其它CPU的线程来说就是不可见的。这种方式可能使每个线程最终拥有这个共享对象的拷贝,每个拷贝都停留在不同的CPU缓存中。

cache

解决这个问题,可以使用Java中的volatile关键字。volatile关键字可以确保你直接从主存中读取一个给定的变量,当变量发生更新总是会被写回到主存中。

#####竞争条件
如果两个或者多个线程共享一个对象,超过一个对象去更新对象上的变量,竞争条件可能就会发生。

race_condition

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/157183.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • SMO算法最通俗易懂的解释[通俗易懂]

    SMO算法最通俗易懂的解释[通俗易懂]我的机器学习教程「美团」算法工程师带你入门机器学习已经开始更新了,欢迎大家订阅~任何关于算法、编程、AI行业知识或博客内容的问题,可以随时扫码关注公众号「图灵的猫」,加入”学习小组“,沙雕博主在线答疑~此外,公众号内还有更多AI、算法、编程和大数据知识分享,以及免费的SSR节点和学习资料。其他平台(知乎/B站)也是同名「图灵的猫」,不要迷路哦~SVM通常用对偶问题来求解,这…

  • jenkins allure_Jenkins

    jenkins allure_Jenkins前言jenkins集成了allure插件,安装插件后运行pytest+allure的脚本即可在jenkins上查看allure报告了。allure安装在运行代码的服务器本机,我这里是用的dock

  • c socket

    c socket"1.socke分类""2.基本操作函数""3.c实现的网络聊天程序"套接字(socket)是一个抽象层,应用程序可以通过它发送或接

  • 各种常用不等式汇总「建议收藏」

    各种常用不等式汇总「建议收藏」对数学中常用的不等式进行了汇总,目前只有结论,没有证明

  • 华为裁员34岁以上程序员,90后的中年危机,即将在职场引爆

    华为裁员34岁以上程序员,90后的中年危机,即将在职场引爆去年,一条职场潜规则走红网络:不要大声责骂年轻人,他们会立刻辞职的,但是你可以往死里骂那些中年人,尤其是有车有房有娃的那些。真实感受到程序员的中年危机在中国,除了从BAT出来的牛人,一般经理层到35岁,总监层到40岁,往后机会真的会少很多了,不是你能不能干的问题,是别人不给机会你干的问题,不要想着什么外国人可以干到50、60,你就要死磕到底,希望后来者早有打算,不要到最后尴尬的时…

  • Linux 镜像文件ISO下载

    Linux 镜像文件ISO下载Linux镜像文件ISO下载地址:https://archive.kernel.org/centos-vault/6.1/isos/x86_64/

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号