文档章节

java 内存模型

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

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;

	}
}

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

© 著作权归作者所有

共有 人打赏支持
呆萌的我
粉丝 3
博文 15
码字总数 15443
作品 0
天津
JVM内存结构 VS Java内存模型 VS Java对象模型

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

Java架构
07/11
0
0
Java并发(1)- 聊聊Java内存模型

引言 在计算机系统的发展过程中,由于CPU的运算速度和计算机存储速度之间巨大的差距。为了解决CPU的运算速度和计算机存储速度之间巨大的差距,设计人员在CPU和计算机存储之间加入了高速缓存来...

knock_小新
07/18
0
0
当我们谈 Java 并发的时候,你们在谈什么?

前言: 很多人在刚开始学 Java 的时候,会觉得多线程是一块难啃的骨头,特别是对于非科班的同学。究其原因,我想主要是因为没有将多线程建立起一种模型,不清楚多线程的问题到底是怎么产生的...

Java大蜗牛
08/02
0
0
从多核硬件架构,看Java内存模型

在了解Java内存模型之前,先来看一下多核硬件架构。 我们应该都知道,计算机在执行程序的时候,每条指令都是在CPU中执行的,而执行的时候,又免不了要和数据打交道。而计算机上面的数据,是存...

消失er
09/02
0
0
终于有人把Java内存模型(JMM)说清楚了

网上有很多关于Java内存模型的文章,在《深入理解Java虚拟机》和《Java并发编程的艺术》等书中也都有关于这个知识点的介绍。但是,很多人读完之后还是搞不清楚,甚至有的人说自己更懵了。本文...

消失er
08/05
0
0

没有更多内容

加载失败,请刷新页面

加载更多

读书(附电子书)|小狗钱钱之白色的拉布拉多

关注公众号,在公众号中回复“小狗钱钱”可免费获得电子书。 一、背景 之前写了一篇文章 《小狗钱钱》 理财小白应该读的一本书,那时候我才看那本书,现在看了一大半了,发现这本书确实不错,...

tiankonguse
31分钟前
0
0
Permissions 0777 for ‘***’ are too open

异常显示: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: UNPROTECTED PRIVATE KEY FILE! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ......

李玉长
33分钟前
0
0
区块链10年了,还未落地,它失败了吗?

导读 几乎每个人,甚至是对通证持怀疑态度的人,都对区块链的技术有积极的看法,因为它有可能改变世界。然而,区块链技术问世已经10年了,我们仍然没有真正的用上区块链技术。 几乎每个人,甚...

问题终结者
今天
2
0
20180921 su与sudo命令、限制root用户通过ssh远程登录

su 命令 用户切换。 su # 切换到root用户su username # 切换到username用户# su 后面加-时,会初始化当前用户的各种环境su - username # 指定用户执行某些命令 su - -c "touch /tm...

野雪球
今天
2
0
Windows 下双 Python 开发环境配置

Windows 下双 Python 开发环境配置作者:老农民(刘启华)QQ: 46715422Email: 46715422@qq.com微信: 46715422 本人曾经在 Windows 下被两个版本环境折腾够呛,现在总结两个 Python...

新疆老农民
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部