文档章节

java 内存模型

呆萌的我
 呆萌的我
发布于 2015/10/13 20:12
字数 1448
阅读 4
收藏 0
点赞 0
评论 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——JVM内存结构(已完结)

Java内存模型,Java内存管理,Java堆和栈,垃圾回收 本文是《成神之路系列文章》的第一篇,主要是关于JVM的一些介绍。 持续更新中 参考文章: Java虚拟机的内存组成以及堆内存介绍 Java堆和栈...

⋅ 05/05 ⋅ 0

《成神之路-基础篇》JVM——垃圾回收(已完结)

Java内存模型,Java内存管理,Java堆和栈,垃圾回收 本文是[《成神之路系列文章》][1]的第一篇,主要是关于JVM的一些介绍。 持续更新中 Java之美[从菜鸟到高手演变]之JVM内存管理及垃圾回收 ...

⋅ 05/05 ⋅ 0

《成神之路-基础篇》JVM——JVM参数及调优(已完结)

Java内存模型,Java内存管理,Java堆和栈,垃圾回收 本文是[《成神之路系列文章》][1]的第一篇,主要是关于JVM的一些介绍。 持续更新中 JVM参数及调优 JVM实用参数系列 成为Java GC专家(5)...

⋅ 05/05 ⋅ 0

面试中关于Java虚拟机(jvm)的问题看这篇就够了

最近看书的过程中整理了一些面试题,面试题以及答案都在我的文章中有所提到,希望你能在以问题为导向的过程中掌握虚拟机的核心知识。面试毕竟是面试,核心知识我们还是要掌握的,加油~~~ 下面...

snailclimb ⋅ 05/12 ⋅ 0

11、Java并发性和多线程-Java内存模型

以下内容转自http://ifeve.com/java-memory-model-6/: Java内存模型规范了Java虚拟机与计算机内存是如何协同工作的。Java虚拟机是一个完整的计算机的一个模型,因此这个模型自然也包含一个内...

easonjim ⋅ 2017/06/15 ⋅ 0

Java 面试知识点解析(三)——JVM篇

前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大部...

我没有三颗心脏 ⋅ 05/16 ⋅ 0

【JVM】 java内存区域与内存溢出异常

前言 此系列博客是读《深入理解java虚拟机》所做的笔记整理。 No1. JVM内存管理这堵墙? 对C和C++的开发人员来说,在内存管理领域,他们既拥有每一个对象的“所有权”,也担负着每一个对象生...

binggetong ⋅ 05/07 ⋅ 0

JAVA虚拟机 JVM 详细分析 原理和优化(个人经验+网络搜集整理学习)

JVM是java实现跨平台的主要依赖就不具体解释它是什么了 ,简单说就是把java的代码转化为操作系统能识别的命令去执行,下面直接讲一下它的组成 1.ClassLoader(类加载器) 加载Class 文件到内...

小海bug ⋅ 06/14 ⋅ 0

聊聊JAVA虚拟机中的垃圾收集器

前言 JAVA虚拟机的垃圾收集器是虚拟机内存的清道夫,它的存在让JAVA开发人员能将更多精力投入到业务研发上。了解垃圾收集器,并利用好这个工具,能更好的保障服务稳定性。这篇文章通过分析J...

lilugoodjob ⋅ 05/13 ⋅ 0

培训云计算学校,虚拟机基本结构讲解

我们要对JVM虚拟机的结构有一个感性的认知。毕竟我们不是编程人员,认知程度达不到那么深入。一个运行时的Java虚拟机实例的天职是:负责运行一个java程序。当启动一个Java程序时,一个虚拟机...

长沙千锋 ⋅ 05/17 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JVM堆的理解

在JVM中,我们经常提到的就是堆了,堆确实很重要,其实,除了堆之外,还有几个重要的模块,看下图: 大 多数情况下,我们并不需要关心JVM的底层,但是如果了解它的话,对于我们系统调优是非常...

不羁之后 ⋅ 昨天 ⋅ 0

推荐:并发情况下:Java HashMap 形成死循环的原因

在淘宝内网里看到同事发了贴说了一个CPU被100%的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造成Race Condition,从而导致死循环。这个事情我4、5年前也经历...

码代码的小司机 ⋅ 昨天 ⋅ 1

聊聊spring cloud gateway的RetryGatewayFilter

序 本文主要研究一下spring cloud gateway的RetryGatewayFilter GatewayAutoConfiguration spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/G......

go4it ⋅ 昨天 ⋅ 0

创建新用户和授予MySQL中的权限教程

导读 MySQL是一个开源数据库管理软件,可帮助用户存储,组织和以后检索数据。 它有多种选项来授予特定用户在表和数据库中的细微的权限 - 本教程将简要介绍一些选项。 如何创建新用户 在MySQL...

问题终结者 ⋅ 昨天 ⋅ 0

android -------- 颜色的半透明效果配置

最近有朋友问我 Android 背景颜色的半透明效果配置,我网上看资料,总结了一下, 开发中也是常常遇到的,所以来写篇博客 常用的颜色值格式有: RGB ARGB RRGGBB AARRGGBB 这4种 透明度 透明度...

切切歆语 ⋅ 昨天 ⋅ 0

CentOS开机启动subversion

建立自启动脚本: vim /etc/init.d/subversion 输入如下内容: #!/bin/bash## subversion startup script for the server## chkconfig: 2345 90 10# description: start the subve......

随风而飘 ⋅ 昨天 ⋅ 0

Nginx + uwsgi @ubuntu

uwsgi 安装 sudo apt-get install python3-pip # 注意 ubuntu python3默认没有安装pippython3 -m pip install uwsgi 代码(test.py) def application(env, start_response): start_res......

袁祾 ⋅ 昨天 ⋅ 0

版本控制工具

CSV , SVN , GIT ,VSS

颖伙虫 ⋅ 昨天 ⋅ 0

【2018.06.19学习笔记】【linux高级知识 13.1-13.3】

13.1 设置更改root密码 13.2 连接mysql 13.3 mysql常用命令

lgsxp ⋅ 昨天 ⋅ 0

LVM

LVM: 硬盘划分分区成物理卷->物理卷组成卷组->卷组划分逻辑分区。 1.磁盘分区: fdisk /dev/sdb 划分几个主分区 输入t更改每个分区类型为8e(LVM) 使用partprobe生成分区的文件:如/dev/sd...

ZHENG-JY ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部