volatile

volatile 资料

吃可爱长大的小学妹 提交于 2020-01-15 08:54:27
volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。 遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。 使用该关键字的例子如下: int volatile nVint; 当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取 的数据立刻被保存。 例如: volatile int i=10; int a = i; //其他代码,并未明确告诉编译器,对 i 进行过操作 int b = i; volatile 指出 i 是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据 放在b中。而优化做法是,由于编译器 发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在b中。而 不是重新从i里面读。这样以来,如果i是一个寄存器变量或者 表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问。 一般说来,volatile用在如下的几个地方: 1、中断服务程序中修改的供其它程序检测的变量需要加volatile; 2、多任务环境下各任务间共享的标志应该加volatile; 3

Java知识整理(10)—— volatile

与世无争的帅哥 提交于 2020-01-15 04:45:10
为什么要用volatile? 为什么要用volatile,它可以解决两个问题: 保证不同线程对同一个变量进行操作时的可见性问题; 禁止进行指令重排序。 1.可见性问题 可见性问题是JAVA并发编程中的基本概念: 官方定义如下: 可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看的见。 为什么出现可见性问题? 在并发编程中,不同的线程在不同的cpu执行着,而CPU的缓存机制长这样: 若线程1运行在CPU1上,线程2运行在CPU2上,当线程1修改了某一个对象的值时,可能会缓存在cache1(若cache1满了则缓存在cache2中,以此内推),没有写进主存,那线程2就无法读到最新的数据,因此不能实现可见性。 volatile的作用就是被volatile修饰的变量被修改时强制立即写进主存中,让cache失效,这样其他读该变量的线程就可以立即读到最新的值。这就是volatile的作用之一。 2.有序性问题 有序性是Java并发编程中的另一概念,有序性指程序执行的顺序按照代码的先后顺序进行,而指令重排序是指在执行程序时,编译器和处理器为了提高代码执行效率,会对没有数据依赖的代码行进行重排序,在保证程序最终结果不受影响的情况下更高效地完成代码的运行。不管怎么重排序,单线程执行结果不会被改变,但会影响多线程并发执行的正确性。 举个栗子: 线程1执行下面这段代码:

线程安全的原子性、可见性与有序性

本秂侑毒 提交于 2020-01-15 04:16:36
原子性: 一个或多个操作在CPU执行过程中不被中断的特性称之为原子性 。线程中执行的操作要么全部执行,要么全部不执行。 Java内存模型中的read、load、assign、use、store和write都可以保证原子性的操作(如果对Java内存模型不熟悉,可以参考我的这篇博文 Java内存模型 ),一般基本数据类型访问读写都是原子性的(long和double的非原子性协议例外,但是基本也不会发生) 如果应用场景需要一个更大范围的原子性保证,我们可以直接使用synchronized关键字,在synchronized块之间的操作也具有原子性。 可见性: 可见性是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。 Java内存模型是通过变量修改之后同步回主内存,在变量读取之前从主内存刷新变量值来实现可见性的。如果一个普通变量在多线程中运行的话,往往不能保证可见性,多个线程都是从主内存中获取变量,这时多个线程并不会先等待某一个线程修改完变量之后,写回主内存,再从主内存获取最新的变量值。 如果要保证可见性的话,我们可以使用volatile关键字,具体原理可以参考我的这篇博文 Java的volatile关键字 ,当然除了volatile关键字之外,synchronized和final关键字也能实现可见性

ConcurrentHashMap源码解析 JDK8

*爱你&永不变心* 提交于 2020-01-14 17:33:54
一、简介 上篇文章 详细介绍了HashMap的源码及原理,本文趁热打铁继续分析ConcurrentHashMap的原理。 首先在看本文之前,希望对HashMap有一个详细的了解。不然看直接看ConcurrentHashMap的源码还是有些费劲的。 相信对HashMap,HashTable有一定了解,应该知道HashMap是不具备线程安全性的,在resize时会丢数据(JDK8),而HashTable虽然保证了线程安全性,但是其是通过给每个方法加Synchronized关键字达到的同步目的。但是都知道Synchronized在竞争激烈的多线程并发环境中,在性能上的表现是非常不如人意的。那在高并发环境中HashMap如何保证线程安全而又不浪费太多性能呢?答案就是Java J.U.C并发包中的ConcurrentHashMap。 依然开局一张图。JDK8中的ConcurrentHashMap数据结构。 呃呵,和HashMap的结构是一样的,没错在数据结构层面,ConcurrentHashMap和HashMap是完全一样的。有了这个基础继续往下看。 二、历史版本 ConcurrentHashMap的历史版本大致分界线在JDK8。也就是可以分为JDK8和JDK8以前版本。 数据结构的区别 在JDK8之前HashMap没有引入红黑树,同样的ConcurrentHashMap也没有引入红黑树

Java多线程编程(三)——volatile详解

穿精又带淫゛_ 提交于 2020-01-14 14:37:26
volatile 关键字和synchronized一样都能够保证线程的同步。 Java语言规范第三版中对volatile的定义如下: java编程语言允许线程 访问共享变量 ,为了确保共享变量能被准确和 一致 的更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁更加方便。如果一个字段被声明成volatile,java线程 内存模型 确保所有线程看到这个变量的值是一致的。 volatile 被称为 轻量级 的 synchronized。 同时,它比synchronized的使用和执行成本会更低,因为它不会引起线程上下文的切换和调度。 一、volatile的特性 补充: 1. Java内存模型 (Java Memory Model, JMM ) JMM是由Java虚拟机规范定义的,用来屏蔽掉Java程序在各种不同的硬件和操作系统对内存的访问的差异,这样就可以实现java程序在各种不同的平台上都能达到内存访问的一致性。 在Java中,Java 堆内存 是存在数据共享的,这些共享数据的通信就是通过JMM来控制的。 JMM决定一个线程对共享数据的写入何时对另一个线程可见。 JMM是一个抽象的结构,它定义了 线程和主内存的关系 : 线程之间的 共享变量 存储在 主内存(Main Memory) 中 每一个线程都有一个私有的 本地内存(Local

Java: Do all mutable variables need to be volatile when using locks?

余生颓废 提交于 2020-01-14 13:51:30
问题 Does the following variable, x, need to be volatile? Or does the manipulation within a utils.concurrent lock perform the same function as a synchronized block (ensuring it's written to memory, and not stored in cpu cache)? myMethod(){ myLock.lock(); x++; myLock.unlock(); } 回答1: Such variables only need to be volatile if they're accessed elsewhere without a lock. For example, as a fast read-only access to a size variable. The lock methods do serve the same purpose as a synchronized block. See

volatile的作用

柔情痞子 提交于 2020-01-14 08:51:29
[转] http://blog.21ic.com/user1/2949/archives/2007/35599.html   一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子: 1). 并行设备的硬件寄存器(如:状态寄存器) 2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 3). 多线程应用中被几个任务共享的变量 回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。 假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。 1). 一个参数既可以是const还可以是volatile吗?解释为什么。 2). 一个指针可以是volatile 吗?解释为什么。 3). 下面的函数有什么错误: int square(volatile int *ptr) { return *ptr * *ptr; }

Does Java synchronized keyword flush the cache?

狂风中的少年 提交于 2020-01-14 08:20:11
问题 Java 5 and above only. Assume a multiprocessor shared-memory computer (you're probably using one right now). Here is a code for lazy initialization of a singleton: public final class MySingleton { private static MySingleton instance = null; private MySingleton() { } public static MySingleton getInstance() { if (instance == null) { synchronized (MySingleton.class) { if (instance == null) { instance = new MySingleton(); } } } return instance; } } Does instance have to be declared volatile in

Java volatile关键字实现原理

冷暖自知 提交于 2020-01-14 04:43:33
场景引入 可见性问题 先来看一张图: 上面的图,是简化版的Java内存模型,一个线程有自己的工作内存,同时还有一个共享的主内存。 线程1和线程2读取数据data时,先从主内存里加载data变量的值到工作内存,然后才可以使用那个值。 假设现在线程1修改了data变量的值为1,然后将这个修改写入到自己的工作内存。那么此时,线程1的工作内存里data的值为1,而主内存里data的值还是0。线程2的工作内存data值也是0。 这就尴尬了,线程1和线程2操作的是用一个变量data,但由于线程本地缓存的存在,导致线程1对data变量的修改,线程2不能及时看到。 这就是Java并发编程中的 可见性问题 : 当一个线程修改某个共享变量的值,其他线程是否能够立即知道这个修改。 值得注意的是,上面的Java内存模型是极其简化的,真实的情况远比上面复杂。 volatile的作用及实现原理 要解决上述可见性问题,我们可以使用 volatile 关键字。 在加入volatile关键字后,线程1只要修改data变量的值,就会在修改工作内存data变量值的同时,强制将修改刷新到主内存中。与此同时,线程2需要读取data变量时,先强制将主内存的值刷新到工作内存中,从而保证线程2每次读取都是最新的值。如下图: volatile工作原理如上所述,其在JVM底层的实现原理, 涉及到内存屏障相关概念 。简单来说

C++ volatile的作用

不想你离开。 提交于 2020-01-14 01:46:35
volatile的作用 2006-10-23 13:44:21 大 中 小 关键在于两个地方: 1. 编译器的优化 (请高手帮我看看下面的理解) 在本次线程内, 当读取一个变量时,为提高存取速度,编译器优化时有时会先把变量读取到一个寄存器中;以后,再取变量值时,就直接从寄存器中取值; 当变量值在本线程里改变时,会同时把变量的新值copy到该寄存器中,以便保持一致 当变量在因别的线程等而改变了值,该寄存器的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致 当该寄存器在因别的线程等而改变了值,原变量的值不会改变,从而造成应用程序读取的值和实际的变量值不一致 举一个不太准确的例子: 发薪资时,会计每次都把员工叫来登记他们的银行卡号;一次会计为了省事,没有即时登记,用了以前登记的银行卡号;刚好一个员工的银行卡丢了,已挂失该银行卡号;从而造成该员工领不到工资 员工 -- 原始变量地址 银行卡号 -- 原始变量在寄存器的备份 2. 在什么情况下会出现(如1楼所说) 1). 并行设备的硬件寄存器(如:状态寄存器) 2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 3). 多线程应用中被几个任务共享的变量 补充: volatile应该解释为“直接存取原始内存地址”比较合适,“易变的”这种解释简直有点误导人; “易变”是因为外在因素引起的