java内存模型(Java Memory Model)
内容导航:
- Java内存模型
- 硬件存储体系结构
- Java内存模型和硬件存储体系之间的桥梁:
- 共享对象的可见性
- 竞争条件
Java内存模型规定了JVM怎样与计算机存储系统(RAM)协调工作。JVM是一个虚拟机模型,因此这个模型自然包含一个内存的模型
理解java内存模型对于设计正确的并发程序非常重要。JVM规定了不同线程何时以及怎样能看到那些被共享变量的读写,怎样同步对共享变量的訪问控制。
最初的java内存模型并不完好。所以他在java1.5中被改动了。以下的内存模型在java1.8中仍然使用。
Java内存模型
JVM中内存模型被划分为栈(stack)和堆(heap)。下图是内存的逻辑图
在JVM中运行的每个线程有自己的栈空间。
每个线程栈包括有线程调用方法当前运行位置的指针。我们把它叫做栈指针。当线程运行他的代码时候,栈指针会改变。共享一块堆空间。
线程栈也包括全部正在被运行的方法的局部变量。一个线程仅仅能訪问他自己的栈。每个线程创建的局部变量对其它线程是不可见的。纵使两个线程正在运行同一段代码,他们也仅仅会创建属于自己栈空间的局部变量。也就是说每个线程有他自己的局部变量,相互之间不影响。
全部的局部基本数据类型(boolean、byte、short、char、int、long、float、double)全然存储在线程栈空间里,而且其它线程不可见。一个线程能够传递自己局部基本数据的拷贝给还有一个线程,可是他们之间并不共享。
堆空间中存放的是应用程序中全部的对象,无论是哪一个线程创建的。
而且包含基本数据对象(eg.Byte,Integer,Long等)。
无论这个对象是作为局部变量被创建,还是作为还有一个对象的成员变量被创建。他都在堆中。即一切对象都在堆空间。
看下图:
一个局部变量可能是基本数据类型。还可能是一个对象的引用。他们都在创建自己的线程栈空间,引用所指向的真正的对象在堆空间。
一个对象的成员方法。而且这些方法中也可能包括局部变量。这些局部变量在所属的线程栈中
一个对象的成员变量,无论是基本类型还是对象的引用。都存在这个堆空间的对象的内部
同一个对象能够被不同的拥有这个对象的引用的线程訪问。而且能够訪问对象的成员变量。
假设两个线程同一时刻调用同样对象的成员方法,他们都能訪问对象的成员变量,可是各自有自己的局部变量的拷贝。
以下的图阐述了上述内容:
硬件存储体系结构:
以下是简单的现代计算机的存储结构:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDY1OTY1Ng==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
现代计算机通常有2个甚至很多其它的CPU,这些CPU中的一些还可能是多核的。
关键点就是多CPU的计算机同意多个线程同一时候执行(是真正的并行而非并发)。每个cpu在给定的时间片执行一个线程。假设java程序是多线程的,每个线程就能够在各个cpu上同一时候执行。
每一个cpu都包括有一系列寄存器。
cpu直接从寄存器运行运算比从内存要快非常多倍。
每个cpu还可能有cpu缓存(我们熟称的cache)。实际上大多数现代cpu都有不同容量的cache。Cpu从cache存取又比从内存快,可是比寄存器又慢一些。一些cpu还有多级缓存(L1、L2等)。可是这并不影响理解java内存模型,我们所要知道的就是在内存和cpu之间另一层缓存cache。
通常,cpu訪问主存的时候须要读一部分到cache。还可能把cache的一部分有读到寄存器,然后运行运算。当cpu须要把运算结果写回到主存的时候,会先把值从寄存器更新到cache,cache放满后再写回主存。
存储在cache中的值通常在cpu须要存储其它的东西时一起被写回到内存。
Cache把里面存储的内容一次性写回到主存。这个过程并不一定读写整个cache。通常情况下是更新cache中更小的单位,叫做cache lines 缓存行。一行或多行cache line会从主存读取到cache。或者从cache被写回主存。
Java内存模型和硬件存储体系之间的桥梁
正如已经提及的,java内存模型和硬件存储体系是不同的。
硬件存储体系并不会区分堆和栈。
在硬件层面上,堆和栈都分配在主存中。堆和栈中的一部分还可能在cache和寄存器中。例如以下图:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDY1OTY1Ng==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
当对象和变量被存储在计算机不同的存储区域(rejister、cache、main-memory)的时候,就会出现故障了。
有两个问题例如以下:
- 线程对共享变量读写的可见性
- 读写检查共享变量的竞争条件
共享对象的可见性
假设两个或者多个线程共享一个对象而没实用volatile声明或者synchronize同步,某一个线程对共享对象的更新对其它线程可能是不可见的。
设想一下一个開始被存在主内存的共享对象。执行在cpu1上的线程把这个共享对象读入到cache。
然后对这个共享对象做更改。
仅仅要cache还没有被刷新到主存,对象的更改版本号对执行在其它cpu的线程就是不可见的。这样一来,每一个线程就使用的是自己对共享对象的拷贝,这些拷贝存储在各自cpu cache中。
以下这幅图阐述了这样的情况。
一个执行在左側cpu的线程把共享对象复制到自己的cpu cache中,而且把count值改为2.这个改变对执行在右側cpu的线程是不可见的。
由于对count的更新并没有刷新到主存。
要解决问题。我们可以使用java的volatilekeyword。Volatilekeyword可以确保被声明的变量直接从主存读取或者是直接在主存更新而不经过cache中间层。
竞争条件
多个线程对共享变量的更新还会引发竞争。
设想线程A读取共享变量的count字段到他的cache,线程B也是。如今线程A对count加1,线程B也是。
如今var1已经被添加两次,每一个cpu一次。
假设这些添加是被顺序运行(先后次序:即A read increament writeback --> B read increament writeback)的,那么变量count将会顺序加1两次。终于结果是原始值加2写回主存。
可是,假设两次添加被并发运行(交叉次序)而没有适当的同步。那么无论是A还是B写回到主存的结果都是原始值加1。虽然做了两次加。
以下是上述问题的图:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDY1OTY1Ng==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
为了解决问题,引入java的synchronized block,让某一系列操作成为原子性的,即不能够被打断(类似数据库中的事务transaction),从而实现不同线程对某一代码块的相互排斥訪问。
翻译原文地址:http://tutorials.jenkov.com/java-concurrency/java-memory-model.html
java内存模型(Java Memory Model)的更多相关文章
- Java内存模型(Java Memory Model,JMM)
今天简单聊聊什么叫做 Java 内存模型,不是 JVM 内存结构哦. JMM 是一个语言级别的内存模型,处理器的硬件模型是硬件级别,Java中的内存模型是内存可见性的基本保证.从而为我们 volati ...
- Java 内存模型- Java Memory Model
多线程越来越多的使用,使得我们需要对它的深入理解.那么就涉及到了Java内存模型JMM.JMM是JVM的一部分,JMM定义了一个线程修改了一个共享变量,其他线程什么时候或者如何看到这个变量,如何去访问 ...
- Java虚拟机12:Java内存模型
什么是Java内存模型 Java虚拟机规范中试图定义一种Java内存模型(Java Memory Model,JMM)来屏蔽掉各种硬件和操作系统的访问差异,以实现让Java程序在各种平台下都能达到一致 ...
- 全面理解Java内存模型
尊重原创:http://blog.csdn.net/suifeng3051/article/details/52611310 Java内存模型即JavaMemory Model,简称JMM.JMM定义 ...
- 【JVM】JVM内存结构 VS Java内存模型 VS Java对象模型
原文:JVM内存结构 VS Java内存模型 VS Java对象模型 Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点.而且很多概念的名称看起来又那么相似,很多人会傻傻分不清 ...
- 全面理解Java内存模型(JMM)及volatile关键字(转载)
关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java类加载器(ClassLoad ...
- Java内存模型学习笔记
Java内存模型(JMM):描述了java程序中各种变量(线程共享变量)的范根规则,以及在JVM中将变量存储到内存和从内存中读取出变量这样的底层细节.共享变量就是指一个线程中的变量在其他线程中也是可见 ...
- 全面理解Java内存模型(JMM)及volatile关键字
[版权申明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/72772461 出自[zejian ...
- 全面理解Java内存模型(JMM)
理解Java内存区域与Java内存模型Java内存区域 Java虚拟机在运行程序时会把其自动管理的内存划分为以上几个区域,每个区域都有的用途以及创建销毁的时机,其中蓝色部分代表的是所有线程共享的数据区 ...
- Java内存模型原理总结(转自51CTO)
转载地址:http://developer.51cto.com/art/201811/587220.htm [51CTO.com原创稿件]这篇文章主要介绍模型产生的问题背景,解决的问题,处理思路,相关 ...
随机推荐
- ogre3D学习基础11 -- 交换两个场景管理器
这一节,练习一下前几次学习的内容,功能很简单,就是建立两个不同的场景管理器,当按下键盘上某个键时切换镜头. 基本框架不变,这个监听器继承了两个父类,一个是我们的老朋友ExampleFrameListe ...
- 聊聊、Java 网络编程
Socket 编程大家都不陌生,Java 学习中必学的部分,也是 Java网络编程核心内容之一.Java 网络编程又包括 TCP.UDP,URL 等模块.TCP 对应 Socket模块,UDP 对应 ...
- 51nod1779 逆序对统计
1779 逆序对统计 基准时间限制:1 秒 空间限制:131072 KB lyk最近计划按顺序做n道题目,每道题目都分为很多分数档次,lyk觉得这些题太简单了,于是它想到了一个好玩的游戏. lyk决 ...
- 广东工业大学2016校赛决赛重现——E积木积水(方法据说很多)
Problem E: 积木积水 Description 现有一堆边长为1的已经放置好的积木,小明(对的,你没看错,的确是陪伴我们成长的那个小明)想知道当下雨天来时会有多少积水.小明又是如此地喜欢二次元 ...
- BZOJ 2501: [usaco2010 Oct]Soda Machine 离散+差分
[usaco2010 Oct]Soda Machine Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 266 Solved: 182[Submit][ ...
- net4:GridView中的重要操作(添加checkbox,以及鼠标动作,行颜色等)
原文发布时间为:2008-07-29 -- 来源于本人的百度文章 [由搬家工具导入] using System;using System.Data;using System.Configuration ...
- AC日记——最优贸易 codevs 1173
题目描述 Description [问题描述]C 国有n 个大城市和m 条道路,每条道路连接这n 个城市中的某两个城市.任意两个城市之间最多只有一条道路直接相连.这m 条道路中有一部分为单向通行的道路 ...
- POJ - 2391 最大流
题目链接:http://poj.org/problem?id=2391 今天掉坑多次. 做了几道题,发现从源点出来的边和进入汇点的边都在题目中出来过. POJ真是坑,交G++一直wa,检查代码检查了好 ...
- HDU 1018.Big Number-Stirling(斯特林)公式 取N阶乘近似值
最近一堆题目要补,一直咸鱼,补了一堆水题都没必要写题解.备忘一下这个公式. Stirling公式的意义在于:当n足够大时,n!计算起来十分困难,虽然有很多关于n!的等式,但并不能很好地对阶乘结果进行估 ...
- (12)ubunto 快捷键
-----------------------------------------------------vi快捷键------------------------------------ 指令模式: ...