码迷,mamicode.com
首页 > 编程语言 > 详细

Java内存模型JMM简单分析

时间:2017-09-24 12:42:42      阅读:229      评论:0      收藏:0      [点我收藏+]

标签:否则   读取   code   alt   target   count   线程创建   img   实现   

参考博文:http://blog.csdn.net/suifeng3051/article/details/52611310

     http://www.cnblogs.com/nexiyi/p/java_memory_model_and_thread.html  

        http://www.cnblogs.com/dolphin0520/p/3613043.html 

 

一、Java内存区域的划分  

由于Java程序是交给JVM执行的,所以我们在谈Java内存区域分析的时候事实上是指JVM内存区域划分。

根据《Java虚拟机规范》的规定,运行时数据区通常包括这几个部分:程序计数器(Program Counter Register)、Java栈(VM Stack)、本地方法栈(Native Method Stack)、方法区(Method Area)、堆(Heap)。

技术分享

 

如上图所示,JVM中的运行时数据区应该包括这些部分。在JVM规范中虽然规定了程序在执行期间运行时数据区应该包括这几部分,但是至于具体如何实现并没有做出规定,不同的虚拟机厂商可以有不同的实现方式。

 

1.程序计数器:用来指示执行哪条命令

  由于在JVM中,多线程是通过线程轮流切换来获得CPU执行时间的,因此,在任一具体时刻,一个CPU内核只会执行一条线程中的指令

  因此,为了能够使得每个线程都在线程切换后能够恢复在切换之前的程序执行位置,每个线程都需要有自己独立的程序计数器,并且不能互相被干扰,否则就会影响到程序的正常执行次序,

  因此可以这么说,程序计数器是每个线程所私有的

 

2.Java栈:Java栈是Java方法执行的内存模型
  Java栈中包含:

  1.局部变量表(方法中局部变量) 2.操作数栈(程序中的所有计算过程都是在借助于操作数栈来完成的)

  3.指向运行时常量池的引用(引用指向运行时常量) 4.方法返回地址(当一个方法执行完毕,要返回之前调用它的地方) 5.附加信息

  由于每个线程正在执行的方法可能不同,因此每个线程都会有一个自己的Java栈,互不干扰

 

3.本地方法栈(为执行本地方法服务的)

  本地方法栈与Java栈类似,区别只不过是Java栈是为执行Java方法服务器的,而本地方法栈则是为执行本地方法(Native Method)服务的

在HotSopt虚拟机中,直接就把本地方法栈和Java栈合二为一

 

4.堆

  Java中的堆是用来存储对象本身的以及数组(当然,数组引用是存放在Java栈中的)。另外,堆是被所有线程共享的,在JVM中只有一个堆


5.方法区

  方法区与堆一样,是被线程共享的区域。在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译后的代码等

 

根据以上,也许可以得出: 

  我们创建一个线程时,会为这个线程分配这个线程的独有的 栈空间 和 堆空间

  栈空间用于执行线程自己的方法

  堆空间存储 从主存中copy过来的对象,以及线程中这个线程创建的变量

  在线程中创建一个变量,会在线程自己的堆空间开辟一块内存,(猜想,主存中也会同步得到这个变量?,还是说对象的创建就是在主存中进行的)

 

二、Java内存模型

技术分享

Java内存模型中规定了所有的变量都存储在主存中,每条线程还有自己的工作内存,线程对变量的所有操作(读取、赋值)都必须在工作内存中进行,而不能直接读写主内存中的变量,不同线程之间无法直接访问对方工作内存中的变量,线程间变量值的传递均需要在主内存来完成

 注:感觉为线程分配的这块内存,包括 一部分栈空间(用来操作变量)和一部分堆空间(用来存储变量)

 

注:线程之间的通信

  线程的通信是指线程之间以何种机制来交换信息。在命令式编程中,线程之间的通信机制有两种 共享内存和消息传递

  消息传递:在java中典型的消息传递方式就是 wait()  和 notify()

  共享内存:通过共享对象进行通信

技术分享

从上图来看,线程A与线程B之间如要通信的话,必须要经历下面2个步骤:

1.首先,线程A把本地内存A中更新过的共享变量刷新到主内存中去。 2. 然后,线程B到主内存中去读取线程A之前已更新过的共享变量。

技术分享

从整体来看,这两个步骤实质上是线程A在向线程B发送消息,而且这个通信过程必须要经过主内存。

 

默认情况下,线程之间的工作内存是不可共享的,即A线程是看不到B线程的工作内存的,B线程从主存中copy了一份变量x,然后对这个变量进行操作

A是看不到B对x做了什么操作的,必须要等B将x的值刷新回内存,线程A才知道

在使用volatile关键字修饰变量x之后呢,volatile保存可见性的原理是在每次访问变量时都会进行一次刷新,因此每次访问都是主存中最新的版本

线程B从主存中copy了一份变量x,此时B对i进行操作后,会立即将更新后x的刷新回主存,A线程读取x的值时,刷新主存,得到的是x的最新值

最后可以理解为,线程是在主存上操作对象x(实际上不是,还是必须要在线程自己的工作空间上操作,只是有这个效果),线程之间 对于x对象都是可见的,

Java内存模型JMM简单分析

标签:否则   读取   code   alt   target   count   线程创建   img   实现   

原文地址:http://www.cnblogs.com/xuzekun/p/7586765.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!