Java并发编程之关键字volatile知识总结

一、作用

被 volatile 修饰的变量

1.保证了不同线程对该变量操作的内存可见性

2.禁止指令重排序

二、可见性

Java 内存模型(Java Memory Model) 是 Java 虚拟机定义的一种规范,即每个线程都有自己的工作空间,线程对变量的操作都在线程的工作内存中完成,再同步到主存中,这样可能会导致不同的线程对共享变量的操作,在各自线程工作空间内不一样的问题。

而用 volatile 修饰的变量,线程对该变量的修改,会立刻刷新到主存,其它线程读取该变量时,会重新去主存读取新值。

三、有序性

CPU 为了提供程序的运行效率,会对代码的执行顺序进行重排,因此代码中各个语句的先后执行顺序有可能会变化,但是它会保证程序最终执行结果与代码顺序执行结果一致。

指令重排序会考虑数据之间的依赖性,不会影响单个线程内程序的执行结果

c = 2 可能在 a = 1之前执行

int a = 1;
int c = 2;

volatile 修饰的变量具有有序性,即被 volatile 修饰的变量,在其前面的操作与在其后面的操作的执行顺序不能打乱。

int a= 1;
volatile b = 2;
int c = 2;

a = 1 一定在 c = 2 前面执行,volatile 的作用好像在两者之间插入了一个内存屏障

对于 volatile 的有序性应用,一般常用 double-check 的单例模式来说明

public class Singleton {
	private Singleton(){}

	private static volatile Singleton singleton;

	public static Singleton getSingleton(){
		if (singleton == null){
			synchronized(Singleton.class){
				if (singleton == null){
					singleton = new Singleton();
				}
			}
		}
		return singleton
	}
}

singleton = new Singleton(); 分为 3 步

1.new Singleton() 开辟堆内存空间

2.初始化 singleton 对象

3.将 singleton 对象指向堆内存地址

第 3 步可能在第 2 步之前执行,那么其它线程可能得到为初始化完成的 singleton 对象,造成异常。

四、happens-before

  • 程序顺序规则: 一个线程中的每个操作,happens-before于该线程中的任意后续操作
  • 监视器锁规则:对一个线程的解锁,happens-before 于随后对这个线程的加锁
  • volatile 变量规则: 对一个 volatile 域的写,happens-before 于后续对这个 volatile 域的读
  • 传递性:如果 A happens-before B ,且 B happens-before C, 那么 A happens-before C
  • start()规则: 如果线程A执行操作ThreadB_start()(启动线程B) , 那么A线程的ThreadB_start()happens-before 于B中的任意操作
  • join()原则: 如果A执行ThreadB.join()并且成功返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作成功返回。
  • interrupt()原则: 对线程interrupt()方法的调用先行发生于被中断线程代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测是否有中断发生
  • finalize()原则:一个对象的初始化完成先行发生于它的finalize()方法的开始

五、与 Synchronized 对比

1.volatile 只能作用于变量,synchronized 可以作用于变量,方法,代码块

2.volatile 不保证原子性,synchronized 可以保证

3.访问 volatile 修饰的变量不会阻塞,synchronized 可能会

到此这篇关于Java并发编程之关键字volatile知识总结的文章就介绍到这了,更多相关Java关键字volatile内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2021-06-08

java volatile关键字作用及使用场景详解

1. volatile关键字的作用:保证了变量的可见性(visibility).被volatile关键字修饰的变量,如果值发生了变更,其他线程立马可见,避免出现脏读的现象.如以下代码片段,isShutDown被置为true后,doWork方法仍有执行.如用volatile修饰isShutDown变量,可避免此问题. public class VolatileTest3 { static class Work { boolean isShutDown = false; void shutdown(

Java并发编程volatile关键字的作用

日常编程中出现 volatile 关键字的频率并不高,大家可能对 volatile 关键字比较陌生,再深入一点也许是听闻 volatile 只能保证可见性而不能保证原子性,无法有效保证线程安全,于是更加避免使用 volatile ,简简单单加上synchronize关键字就完事了.本文稍微深入探讨 volatile 关键字,分析其作用及对应的使用场景. 并发编程的几个概念简述 首先简单介绍几个与并发编程相关的概念: 可见性 可见性是指变量在线程之间是否可见,JVM 中默认情况下线程之间不具备可见

深入了解Java中Volatile关键字

一.基本概念 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情.为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制. 可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的.也就是一个线程修改的结果.另一个线程马上就能看到.比如:用volatile修饰的变量,就会具有可见性.volatile修饰

Java多线程之volatile关键字及内存屏障实例解析

前面一篇文章在介绍Java内存模型的三大特性(原子性.可见性.有序性)时,在可见性和有序性中都提到了volatile关键字,那这篇文章就来介绍volatile关键字的内存语义以及实现其特性的内存屏障. volatile是JVM提供的一种最轻量级的同步机制,因为Java内存模型为volatile定义特殊的访问规则,使其可以实现Java内存模型中的两大特性:可见性和有序性.正因为volatile关键字具有这两大特性,所以我们可以使用volatile关键字解决多线程中的某些同步问题. volatile

一文精通Java中的volatile关键字

前言 在一些开源的框架的源码当中时不时都可以看到volatile这个关键字,最近特意学习一下volatile关键字的使用方法. volatile 关键字:当多个线程进行操作共享数据时,可以保证内存中的数据可见. 相较于 synchronized 是一种较为轻量级的同步策略. 缺点: 1. volatile 不具备"互斥性" 2. volatile 不能保证变量的"原子性" 很多资料中是这样介绍volatile关键字的: volatile是轻量级的synchroniz

JAVA并发中VOLATILE关键字的神奇之处详解

并发编程中的三个概念: 1.原子性 在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行. 2.可见性 对于可见性,Java提供了volatile关键字来保证可见性. 当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值. 而普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保

Java并发编程——volatile关键字

一.volatile是什么 volatile是Java并发编程中重要的一个关键字,被比喻为"轻量级的synchronized",与synchronized不同的是,volatile只能修饰变量,无法修饰方法及代码块等. 下面是使用volatile关键字实现的单例模式: public class Singleton implements Serializable { private static volatile Singleton singleton; private Singleto

Java 并发编程:volatile的使用及其原理解析

Java并发编程系列[未完]: •Java 并发编程:核心理论 •Java并发编程:Synchronized及其实现原理 •Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) •Java 并发编程:线程间的协作(wait/notify/sleep/yield/join) •Java 并发编程:volatile的使用及其原理 一.volatile的作用 在<Java并发编程:核心理论>一文中,我们已经提到过可见性.有序性及原子性问题,通常情况下我们可以通过Synchroniz

Java并发编程-volatile可见性详解

前言 要学习好Java的多线程,就一定得对volatile关键字的作用机制了熟于胸.最近博主看了大量关于volatile的相关博客,对其有了一点初步的理解和认识,下面通过自己的话叙述整理一遍. 有什么用? volatile主要对所修饰的变量提供两个功能 可见性 防止指令重排序 <br>本篇博客主要对volatile可见性进行探讨,以后发表关于指令重排序的博文. 什么是可见性? 把JAVA内存模型(JMM)展示得很详细了,简单概括一下 1.每个Thread有一个属于自己的工作内存(可以理解为每个

Java多线程并发编程 Volatile关键字

volatile 关键字是一个神秘的关键字,也许在 J2EE 上的 JAVA 程序员会了解多一点,但在 Android 上的 JAVA 程序员大多不了解这个关键字.只要稍了解不当就好容易导致一些并发上的错误发生,例如好多人把 volatile 理解成变量的锁.(并不是) volatile 的特性: 具备可见性 保证不同线程对被 volatile 修饰的变量的可见性. 有一被 volatile 修饰的变量 i,在一个线程中修改了此变量 i,对于其他线程来说 i 的修改是立即可见的. 如: vola

Java并发编程:volatile关键字详细解析

volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以重获生机. volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事情.由于volatile关键字是与Java的内存模型有关的,因此在讲述volatile关键之前,我们先来了解一下与内存模型相关的概念和知识,然后分析了volatile关键字的实现原理,最后给出了几个使用vola

深入分析java并发编程中volatile的实现原理

引言 在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的"可见性".可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值.它在某些情况下比synchronized的开销更小,本文将深入分析在硬件层面上Inter处理器是如何实现Volatile的,通过深入分析能帮助我们正确的使用Volatile变量. 术语定义 术语 英文单词 描述 共享变量 在多个线

Java 并发编程之线程挂起、恢复与终止

挂起和恢复线程 Thread 的API中包含两个被淘汰的方法,它们用于临时挂起和重启某个线程,这些方法已经被淘汰,因为它们是不安全的,不稳定的.如果在不合适的时候挂起线程(比如,锁定共享资源时),此时便可能会发生死锁条件--其他线程在等待该线程释放锁,但该线程却被挂起了,便会发生死锁.另外,在长时间计算期间挂起线程也可能导致问题. 下面的代码演示了通过休眠来延缓运行,模拟长时间运行的情况,使线程更可能在不适当的时候被挂起: public class DeprecatedSuspendResume

Java 并发编程学习笔记之核心理论基础

并发编程是Java程序员最重要的技能之一,也是最难掌握的一种技能.它要求编程者对计算机最底层的运作原理有深刻的理解,同时要求编程者逻辑清晰.思维缜密,这样才能写出高效.安全.可靠的多线程并发程序.本系列会从线程间协调的方式(wait.notify.notifyAll).Synchronized及Volatile的本质入手,详细解释JDK为我们提供的每种并发工具和底层实现机制.在此基础上,我们会进一步分析java.util.concurrent包的工具类,包括其使用方式.实现源码及其背后的原理.本

深入理解Java中的volatile关键字(总结篇)

基本概念 -------------------------------------------------------------------------------- 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情.为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制. 可见性,是指线程之间的可见性,一个