文档章节

java 内存模型

呆萌的我
 呆萌的我
发布于 2015/10/13 20:12
字数 1448
阅读 20
收藏 0

精选30+云产品,助力企业轻松上云!>>>

java模型规定:所有变量都要存储在主内存(Main Memory)中,每一个线程都有自己的工作内存(Working Memory),线程中的工作内存中保存了被该线程使用的变量的主内存副本拷贝,线程对变量的操作(读取,复制)都必须在工作内存进行,而不能直接读写内存中的变量。而不同线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递均需要通过主内存完成。

学过操作系统的都应该明白,高速缓存为了缓解CPU与硬件的速度差等问题,主内存对应的是物理硬件,为了提高运行速度,虚拟机会让工作内存有限存储与寄存器和高速缓存中,因为程序运行时主要读写的工作内存。

主内存和工作内存之间有8种操作完成,虚拟机实现每个操作都是原子的,不可再分的:

  • luck: 作用在主内存的变量,它把一个变量标示为一条线程独占的状态。
  • unluck: 作用在主内存的变量,它把一个处于锁定状态的变量释放出来,给其他线程访问。
  • read: 作用在主内存的变量,它把一个变量从主内存传输到线程的工作内存中,以便随后的load动作使用。
  • load: 作用在工作内存的变量,它把read操作从主内存中得到的变量放在工作内存变量的副本中。
  • use: 作用在工作内存的变量,它把工作中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用的变量的值的字节码指令时将会执行这个操作。
  • assign: 作用在工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令式执行这个操作。
  • store: 作用在工作内存的变量,它把工作内存中一个变量的值传送到主内存中,以便随后的write操作使用。
  • write: 作用在主内存的变量,它吧store操作从工作内存中得到的变量值放入主内存的变量中。
把一个变量从主内存复制到工作内存时,必须顺序执行read 和 load ,
把一个变量从工作内存复制到主内存时,必须顺序执行store 和 write。
但是,不需要连续执行,他们之间可以插入其他的指令,
如 访问内存中a  , b  可能执行read a  read b load b load a。

volatile 变量特殊规则:
这个java 提供的轻量级同步机制,很难理解。
首先,一个volatile 变量具有两种属性:
1.保证变量对所有线程的可见性,当一个线程改变了,新值对其他线程是立即可见的,而普通变量,必须将值由工作线程传递给主内存。
很多人认为被volatile就能实现 并发的一致性,但是被volatile修饰的变量运算不一定是线程安全的,网友们一般都那自增来举例,同样,我们来看一个。

package cn.pmax;

public class VolatileTest {

	private static volatile int count = 0;

	public static void main(String[] args) {

		//开启100个线程 自增count
		for (int i = 0; i < 100; i++) {
			new Thread(new Runnable() {

				@Override
				public void run() {
					try {
						Thread.sleep(20);			//延时20毫秒 增强实验效果
					} catch (InterruptedException e) {
					}

					count++;

				}
			}).start();
		}

		while (Thread.activeCount() > 1)<span style="white-space:pre">				//让所有开启线程都结束
			Thread.yield();

		System.out.println(count);

	}

}
可以看到 得到的结果并非是100,因为++在jvm编译后 生成了多条指令。

  static int access$008();

    Code:

       0: getstatic     #1                  // Field count:I

       3: dup           

       4: iconst_1      

       5: iadd          

       6: putstatic     #1                  // Field count:I

       9: ireturn     


我们可以看到,自增操作分成了两步(4,5)当执行到 4时 有其他线程进来操作了过期数据,使结果变小。
所以,volatile 变量职能保证可见行,但是不能保证原子行。

volatile多用于两种情况:
1.运算不依赖当前值,
2.并发时 作为 状态标签

两个常用例子:

volatile boolean asleep;
	while(!asleep) {
		//TODO ....
	}

当asleep状态发生改变时,while语句会立即终止。




饭后继续。。。。。


2.禁止指令重排序优化。
一个因优化引发的血案

public class Singleton {

	private static Singleton intance;

	private Singleton() {}

	public synchronized static Singleton getInstance() {
		if (intance == null) {
			intance = new Singleton();
		}
		return intance;
	}
}

因为 synchronized 加在方法上降低性能,所以有人提出了双重锁检查

if (instance == null) {
			synchronized (Singleton.class) {
				if (instance == null)
					instance = new Singleton();
			}
		}

貌似很完美的解决了性能问题,但是由于对jvm虚拟机不熟,引来了一个潜在的问题,可能导致 获得一个还没有完成的初始化对象。

我们JIT生成反汇编代码发现 new 一个对象时 分为三步,
memory = allocate();   //1:分配对象的内存空间
ctorInstance(memory);  //2:初始化对象
instance = memory;     //3:设置instance指向刚分配的内存地址
由于jvm会对指令重排序,所以可能 执行完成1后 执行 3 这时候还没有初始化对象,当一个线程到达最外层的if判断时,instance不为null 直接返回了一个没有完成初始化的对象。

所以jdk 5 后给 属性加volatile 即可 防止指令重排序来解决线程安全问题。


public class Singleton {

	private volatile static Singleton instance = null;

	private Singleton() {}

	public static Singleton getInstance() {

		if (instance == null) {
			synchronized (Singleton.class) {
				if (instance == null)
					instance = new Singleton();
			}
		}
		return instance;

	}
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

呆萌的我
粉丝 4
博文 15
码字总数 15443
作品 0
天津
私信 提问
加载中
请先登录后再评论。
JVM内存结构 VS Java内存模型 VS Java对象模型

前面几篇文章中, 系统的学习了下JVM内存结构、Java内存模型、Java对象模型, 但是发现自己还是对这三者的概念和区别比较模糊, 傻傻分不清楚。所以就有了这篇文章, 本文主要是对这三个技术点再...

osc_kiqfrd7o
2018/07/02
2
0
https://blog.51cto.com/13732225/2133741

Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模型和...

茅茹
2019/06/12
0
0
JVM内存结构 VS Java内存模型 VS Java对象模型

Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模型和...

中琦2513
03/31
0
0
JVM内存结构、 Java内存模型、 Java对象模型

Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模型和...

osc_tgjycqas
2018/07/30
22
0
Java之JVM内存结构、Java内存模型、Java对象模型

Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模型和...

郑加威
2017/01/13
133
0

没有更多内容

加载失败,请刷新页面

加载更多

IntelliJ IDEA 默认快捷键大全

Remember these Shortcuts 常用 功能 快捷键 备注 ● Smart code completion Ctrl + Shift + Space - ● Search everywhere Double Shift - ● Show intention actions and quick-fixes Alt......

巨輪
35分钟前
18
0
Hacker News 简讯 2020-07-14

更新时间: 2020-07-14 01:01 I Know What You Download on BitTorrent - (iknowwhatyoudownload.com) 我知道你在BitTorrent上下载了什么 得分:196 | 评论:159 Show HN: Primo – all-in-one......

FalconChen
今天
114
0
绕过移动端系统限制的 dlopen 库 byOpen

byOpen是一个绕过移动端系统限制的增强版dlfunctions库。 支持特性 Android 支持App中加载和使用Android系统库接口(即使maps中还没有被加载也支持)。 Android 7以上dlopen, System.load都是...

shzwork
昨天
25
0
Golang学习系列第二天:变量、常量、数据类型和流程语句

继golang第一天后,今天学习下golang的变量、常量、数据类型和控制流语句。 做过其他编程语言(比如JavaScript,java,python)项目的话,其实很好理解变量、常量、数据类型和控制流。 变量也...

董广明
昨天
48
0
redis系列之——一致性hash算法

一致性hash算法你了解吗?什么时候使用?解决什么问题?redis集群模式使用了一致性hash算法了吗? 数据分片(sharding) 分布式数据存储时,经常要考虑数据分片,避免将大量的数据放在单表或...

诸葛小猿
昨天
15
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部