volatile原理浅析

在多线程并发变成中,volatile是扮演者重要的角色,下面主要从使用、原理来分析:

使用方法:

public class volatileTest {
	
	//将成员变量声明为volatile
	volatile long  vl = 0L;
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}

原理:

定义:(引自Java语言规范第三版)Java编程语言允许多线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过拍他所单独获取这个变量。Java提供了volatile,在某些请鲁昂下比锁更加方便,一旦该成员变量被声明为volatile 所有读取这个变量的线程看到的这个值都是一致的。


白话版定义:Java支持多线程同时访问一个对象或者对象的成员变量,由于每个线程可以拥有这个变量的拷贝,所以一个线程在执行过程中看到变量不一定是最新的。关键字volatile可以用来修饰成员变量,就是告知程序任何对该变量的访问均需要从共享内存中获取,而对他的改变必须同步刷新到共享内存,他能保证所有线程对变量访问的可见性



确保内存可见性:在volatile修饰的共享变量会在写操作的时候的在其代码中加上lock前缀指令,用来完成这个任务--->将当前处理器缓存航的数据回写到系统内存(共享内存),从而使其他CPU里缓存了该内存地址的数据无效,在多处理器下,通过实现缓存一致性协议,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器缓存行设置为无效,当处理器对这个数据进行操作的时候,会重新从系统内存(共享内存)中把数据读取到处理器的缓存里。


volatile特性:

  • 对一个volatile变量的读,总是能看到任意线程对这个volatile变量最后的写入
  • 即使是64位的long或者double类型变量,只要他是volatile类型,对该变量的读写都具有原子性
  • 如果是多个volatile操作,类似valotile++ 等复合操作,则不具有原子性

volatile读的内存语义:

当读一个volatile变量时,JMM( Java内存模型),会把该线程对应的本地内存置为无效,线程接下来将从朱内存中(共享内存)中读取共享变量。

volatile写的内存语义:

当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到朱内存中(共享内存,之所以说主内存是相对线程自己的内存而言)。

valatile内存语义的实现:

基于保守策略的JMM内存屏障插入策略:
  • 在每个volatile写操作的前面插入一个StoreStore屏障
  • 在每个volatile写操作的后面插入一个StoreStore屏障
  • 在每个volatile读操作的后面插入一个LoadLoad屏障
  • 在每个volatile读操作的后面插入一个LoadStore屏障
注:内存屏障:是一组处理器指令,用于实现对内存操作的顺序限制
    
内存屏障类型
屏障类型指令示例说明
LoadLoad BarriersLoad;LoadLoad;Load2确保Load1数据的装载先于oad2及所有后续装载指令的装载
StoreStore BarriersStore1;StoreStore;Store2确保Store1数据对其他处理器可见(刷新到内存)先于Sotre2以及所有后续存储执行的存储
LoadStore BarriersLoad1;LoadStore;Store2确保Load1数据装载先于Store2及所有后续的存储指令刷新到内存
StoreLoad BarriersStore1;StoreLoad;Load2确保Store1数据对其他处理器变得可见(指刷新到内存)先于Load2及所有后续装载指令的装载
StoreLoad Barriers 会使该屏障之前的所有内存访问指令完成之后,才执行该内存屏障之后的内存访问指令

内存屏障代码分析和释义:

package com.hhx.offline_tools.encode;

public class volatileTest {
	
	int a;
	volatile int v1 = 1;
	volatile int v2 = 2;
	
	void readAndWriteVolatile() {
		/**
		 * 第一个volatile读
		 * 
		 * 在第一个volatile读 和第二个volatile读之间 插入了LoadLoad屏障
		 * 用来禁止上面volatile读和下面的volatile读重排序
		 * 
		 * 同时这里还省略了一个LoadStore屏障,因为下面的普通写根本不可能越过上卖弄的volatile读
		 * 
		 */
		int i = v1;
		/**
		 * 第二个volatile读
		 *
		 * 第二个volatile读和普通写之间
		 * 这里省略了LoadLoad屏障,因为下面根本没有普通读操作
		 * 这里插入了一个LoadStore内存屏障 用来禁止下面的普通写和上面的volatile读重排序
		 */
		int j = v2;
		/**
		 *普通写
		 *
		 *普通写和第一个volatile写之间 插入了 一个StoreStore屏障 用来禁止上面的普通写和下面的volatile写重排序
		 *
		 */
		a = i + j;
		/**
		 * 第一个volatile 写
		 * 
		 *  在第一一个volatile 写和第二个volatile写  之间省略了StoreLoad 屏障,仅仅插入StoreStore屏障即可,因为下面跟着一个volatile
		 *  
		 *  同时在这里还插入了一个StoreStore屏障 用来禁止上卖弄的volatile写与下面的volatile写 重排序
		 *  
		 */
		v1 = i + 1;
		/**
		 * 第二个volatile写
		 * 
		 *  在第二个volatile写之后 加入了StoreLoad 屏障 用来防止上面的volatile写与后面可能有的volatile读写重排序
		 *  这一步不能省略,因为在第二个volatile写之后,方法立即return 此时编译器肯恩无法准确判定后面是否会有volatile读或者写
		 *  为了安全起见,编译器通常会在这里插入一个StoreLoad屏障
		 */
		v2 = j + 2;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值