Java volatile关键字详解

原创 2018年04月15日 16:37:18

Java  volatile关键字详解

volatile关键字的语义:

1、定义为volatile的变量保持对所有线程的立即可见性,但并不意味着在并发下对volatile关键字修饰的变量进行操作是线程安全的。

2、volatile变量将禁用指令重排列优化

 

对于第一点的说明;

volatile变量能够保持对所有线程的立即可见性,这半句的实现基于两点:1、volatile变量的写操作总是立即同步到主内存中 ,2、volatile变量在使用前总是立即从主内存中刷新的。关于主内存的说明参照Java线程模型。

关于第一点的后半句“volatile变量在并发读写下并不是安全的“,即便volatile变量在使用前总是立即从主内存中拿到最新的值,但read这一对虚拟机来说保证了原子性的操作在底层的机器码实现上并不是原子的,也就是说在read这一过程中volatile变量在主内存上的值还是有可能发生改变,这就导致read操作拿到了一个过期的值。

对于第二点的说明:

需要举一个例子。

package ryo;

public class Test {
	
	private int flag = 0;
	private int[] arr;
	
	public static void main(String[] args) {		
		new Test().twoThread();		
	}
	
	public void twoThread() {
		new Thread(new Runnable() {
			@Override
			public void run() {
				while(flag != 1) {
				}
				System.out.println(arr[4]);
			}		
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				arr = new int[5];
				flag = 1;
			}
		}).start();
	}

}


在上边这段代码中,可能因为底层的指令重排列优化导致在第二个线程中的int flag = 1发生在初始化数组之前,这就会导致第一个线程System.out.println(arr[4])抛出异常。

虽然实际上不太可能发生这个问题,即便是int flag = 1先于数组初始化发生,在线程一执行到打印语句之前,线程二也差不多把数组初始化的工作完成了,但理论上是由可能出错的。

这时候需要利用volatile禁用重排列的功能了。

给int flag加上volatile关键字,将保证int flag = 1 后于初始化语句执行,问题就解决了。

写到这里的时候突然想到一个问题,Java内存模型中存在一条既定规则,称之为程序次序规则,规定同一线程中书写在前面的操作先行发生于书写在后面的操作,那岂不是跟指令重排列优化相矛盾了吗?

照这条规则所言,上述例子中线程二的数组初始化不是一定发生在flag = 1之前吗?

反复翻了几遍书又在网络上找了相关问题的说法,对于这个问题的解释应该是这样:

程序次序规则只是保证同一方法的结果不变,也就是说具有逻辑关系的代码是有严格的先后顺序的,而不具有逻辑关系的代码是可以被重排列优化的。

举个例子说:

    public void test() {
       String str1 = "abc";
       String str2 = str1 + "def";
   }

对于这两行代码,第二行就不可能被重排列优化调整到先于第一行之前执行,因为它们具有先后的逻辑关系,这也正是程序次序规则所保证的。

而如果改成这样:

    public void test() {
       String str1 = "abc";
       String str2 = "def";
   }

str2的初始化就有可能被放到str1之前了。

 

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/My_dearest_/article/details/79950460

java的内存模型与volatile关键字详解

由于各种硬件及操作系统的内存访问差异,java虚拟机使用java内存模型(java Memory Model,JMM)来规范java对内存的访问。这套模型在jdk 1.2中开始建立,经jdk 1.5的...
  • wthfeng
  • wthfeng
  • 2017-02-05 10:19:48
  • 863

java volatile关键字(及使用场景)

当一个变量被定义为volatile之后,就可以保证此变量对所有线程的可见性,即当一个线程修改了此变量的值的时候,变量新的值对于其他线程来说是可以立即得知的。可以理解成:对volatile变量所有的写操...
  • x_i_y_u_e
  • x_i_y_u_e
  • 2016-02-24 10:55:24
  • 2642

java中的volatile关键字的功能详解

Cookie的应用场景: 1,记录用户的登陆状态,提示用户是否记住密码; 2,购物车购物功能; 我们知道,在web开发过程中,我们都要和cookie打交道,有时候离开了cookie还真玩不转。co...
  • reggergdsg
  • reggergdsg
  • 2015-12-11 22:01:24
  • 2582

java多线程(四)关键字volatile

关键字volatile的主要作用是使变量在多线程间可见。       解决异步死循环       如下代码       public class RunThread extends Thread...
  • lxy344x
  • lxy344x
  • 2016-06-22 21:18:06
  • 685

Java线程安全之volatile关键字

我们知道在多线程的场景下,线程安全是必须要着重考虑的。Java语言包含两种内在的同步机制:同步块(synchronize关键字)和 volatile 变量。但是其中 Volatile 变量虽然使用简单...
  • Roy_70
  • Roy_70
  • 2017-04-07 10:37:02
  • 3761

Java 关键字volatile 与 synchronized 作用与区别

1,volatile    volatile告诉jvm, 它所修饰的变量不保留拷贝,直接访问主内存中的。   在Java内存模型中,有main memory,每个线程也有自己的memory (例如...
  • HGuang_ZJH
  • HGuang_ZJH
  • 2014-04-13 23:10:42
  • 4260

Java关键字系列 — volatile、synchronized、lock

volatile、synchronized和lock简单介绍
  • u011760575
  • u011760575
  • 2017-01-04 00:01:57
  • 525

Java关键字volatile,原子性,变量可见性

内存模型与CPU缓存 本来CPU计算的数字都是从主从main memory中读取的,但是CPU运行的速度比计算机读取内存的速度快,为了补齐这个短板,所以出现了CPU缓从这种东西。 在多CPU...
  • Matthewhou
  • Matthewhou
  • 2017-07-20 14:49:56
  • 420

面试题--java中volatile关键字的含义

本文转载自:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html在java线程并发处理中,有一个关键字volatile的使用目...
  • Mrzhoug
  • Mrzhoug
  • 2016-08-20 14:58:36
  • 653

Java线程面试题(03) Java中的volatile如何工作? Java中的volatile关键字示例

什么是Java中的volatile变量以及何时使用Java中的volatile变量是一道Java面试中经常被问及的多线程访问问题。尽管许多程序员知道什么是volatile变量,但是他们在回答第二部分问...
  • u010096900
  • u010096900
  • 2017-11-27 13:03:50
  • 703
收藏助手
不良信息举报
您举报文章:Java volatile关键字详解
举报原因:
原因补充:

(最多只允许输入30个字)