Java虚拟机内存模型

了解Java虚拟机的内存模型,有助于我们明白为什么会发生线程安全问题.

上面这幅图是<深入理解Java虚拟机-JVM高级特性与最佳实践>的书中截图.

线程共享的变量会保存在主内存中(Main Memory).

而线程共享的变量的副本会保存在每个线程各自的工作内存中(Working Memory).

线程对于共享变量的所有操作(读取,赋值等)都必须在工作内存中进行,不能直接读写主内存的变量.

不同的线程之间,也无法访问其他线程的工作内存.线程之间的变量传递需要通过主内存来完成.

所以发生线程安全问题的根源就在于,当共享变量在主内存中被修改后,有的线程的工作内存保存的还是该被修改的共享变量的旧的值,就导致了数据不一致的后果.

Volatile型变量

被Volatile修饰的变量,是轻量化的解决部分线程安全问题的方法,它具有2种特性:

1. 保证此变量对于所有线程的可见性,指当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的.

但是这里所说的立即得知,也并不能保证Volatile就能完全避免线程安全数据一致的问题.

private volatile int race = 0;

private void increase() {
race++;
}

比如上面代码,如果多线程的调用increase()方法,是并不能保证线程安全,而且是很有可能发生数据不一致的问题.

原因在于,虽然volatile保证了race变量的修改被其他线程立即得知,但是本身race++这行代码并不是原子操作.实际代码编译后会变成多条字节码.

volatile的使用场景需要符合2条规则:

1) 运算结果并不依赖变量的当前值,或者能够确保只有单一的线程修改变量的值;

2) 变量不需要与其他的状态变量共同参与不变约束.

volatile型变量的经典使用场景是如下这种.当doSomthing()方法被多线程调用时候,只需把shutDown=true之后,所有线程就不会在进行下一轮的while.

private volatile boolean shutDown = false;

private void doSomething() {
while (!shutDown) {
// do something
}
}

2. 使用Volatile变量能禁止指令重排序.

普通的变量仅仅会保证在该方法的执行过程中所有依赖赋值结果的地方都能获取到正确的结果,而不能保证变量赋值操作的顺序与程序代码中的执行顺序一致.因为在一个县城的方法执行过程中无法感知到这点.

public VolatileExample {
Map configOptions;
char[] configText;
volatile boolean initiallized = false; private void init() {
configOptions = new HashMap();
configText = readonfigFile(fileName);
processConfigOptions(configText, configOptions);
initialized = true;
} private void do() {
while (!initialized) {
sleep();
}
doSomethingWithconfig();
}
}

上面这段代码,假设init()方法和do()方法运行再不同的线程中.如果initialized变量没有使用volatile修饰的话,init()方法可能由于指令重排序的优化(指令重排序是机器级的优化操作,提前执行时指这句话对应的汇编代码会被提前执行),导致最后一句代码initialized=true被提前执行.这种情况的后果就是do()方法因为initialized=true就跳过了while循环去执行doSomethingWithConfig()了,但其实可能init()的方法还未运行结束.

而volatile关键字可以避免此类情况的发生.

Java虚拟机内存模型和volatile型变量的更多相关文章

  1. Java线程角度的内存模型和volatile型变量

    内存模型的目标是定义程序中各个变量的访问 规则,即在虚拟机中将变量(包括实例字段,静态字段和构成数组对象的元素,不包括局部变量与方法参数,因为后者是线程私有的)存储到内存和从内存中取出变量这样的底层细 ...

  2. 并发一:Java内存模型和Volatile

    并发一:Java内存模型和Volatile 一.Java内存模型(JMM) Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和在内存中取出变量的底层细节,是围绕着 ...

  3. 黑马-----内存模型和volatile详解

    黑马程序员:Java培训.Android培训.iOS培训..Net培训 JAVA线程-内存模型和volatile详解 一.单核内存模型 1.程序运行时,将临时数据存放到Cache中 2.将CPU计算所 ...

  4. JAVA内存模型和Happens-Before规则

    前言 上一篇文章王子给大家介绍了并发编程中比较关心的三个核心问题,可见性.有序性和原子性. 今天我们继续来探索并发编程的内容,聊一聊JAVA的内存模型和Happens-Before规则. JAVA内存 ...

  5. Java内存模型和JVM内存管理

    Java内存模型和JVM内存管理   一.Java内存模型: 1.主内存和工作内存(即是本地内存): Java内存模型的主要目标是定义程序中各个变量的访问规则,即在JVM中将变量存储到内存和从内存中取 ...

  6. 【Java】JMM内存模型和JVM内存结构

    JMM内存模型和JVM内存结构 JAVA内存模型(Java Memory Model) Java内存模型,一般指的是JDK 5 开始使用的新的内存模型,主要由JSR-133: JavaTM Memor ...

  7. Java 内存模型和 JVM 内存结构真不是一回事

    这两个概念估计有不少人会混淆,它们都可以说是 JVM 规范的一部分,但真不是一回事!它们描述和解决的是不同问题,简单来说, Java 内存模型,描述的是多线程允许的行为 JVM 内存结构,描述的是线程 ...

  8. JVM内存结构、Java内存模型和Java对象模型

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

  9. Java内存模型和ConcurrentHashMap 1.7源码分析

    简介 ConcurrentHashMap 是 util.concurrent 包的重要成员.本文将结合 Java 内存模型,分析 JDK 源代码,探索 ConcurrentHashMap 高并发的具体 ...

随机推荐

  1. texterea 水平居中

    例子:<div style="width: 100%;text-align: center;"> <textarea class="xinde_msg& ...

  2. day 9 追踪一个蓝色的物体

    # -*- coding: utf- -*- import cv2 import numpy as np #.打开摄像头 cap=cv2.VideoCapture('output.avi') ): # ...

  3. 《Node.js 包教不包会》

    <Node.js 包教不包会> 为何写作此课程 在 CNode(https://cnodejs.org/) 混了那么久,解答了不少 Node.js 初学者们的问题.回头想想,那些问题所需要 ...

  4. 关于nginx反向代理504 gateway time-out配置

    问题描述: 使用nginx的默认配置用作后端处理服务的反向代理,针对处理时间超过1分钟的请求,返回504 gateway time-out,但后端服务还在执行中. 原因分析: nginx代理默认超时时 ...

  5. XAF-如何在详细视图界面显示按钮(含示例项目下载)

    默认情况下,指定了按钮的Category后,将在对应的按钮容器显示按钮.有时候,我们需要将按钮显示在详细视图中. 本示例源码 创建一个控制器,并填加按钮.设置好了所有ID.Caption后,给Cate ...

  6. 用php做个简单的日历

    存档: index.php <html> <head> <title>日历</title> <style> table{border:1px ...

  7. 区块链技术:每位CEO都应了解

    区块链技术有可能成为一项广泛应用的突破性技术,像蒸汽机.电力或因特网那 样,改变整个社会和经济的运行方式. 对企业而言,信任至关重要.今天,我们基于信任,将钱存放在银行,通过电商企业 网购产品,并且依 ...

  8. sqlserver(2012)清理tempdb

    当数据库运行时间长了之后,tempdb变得特别大,几十G,受不了啊:当然我们知道重启 SQL Server服务的话,tempdb数据库会自动重新创建的,从而使 tempdb 回归到初始大小.但是这是生 ...

  9. PReLU——Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification

    1. 摘要 在 \(ReLU\) 的基础上作者提出了 \(PReLU\),在几乎没有增加额外参数的前提下既可以提升模型的拟合能力,又能减小过拟合风险. 针对 \(ReLU/PReLU\) 的矫正非线性 ...

  10. 深度学习-tensorflow学习笔记(2)-MNIST手写字体识别

    深度学习-tensorflow学习笔记(2)-MNIST手写字体识别超级详细版 这是tf入门的第一个例子.minst应该是内置的数据集. 前置知识在学习笔记(1)里面讲过了 这里直接上代码 # -*- ...