volatile的一些基本用法

本文探讨了在多线程环境下,JVM如何对代码进行重排序以提升性能,以及这种重排序可能导致的问题。通过一个具体例子说明了当线程间存在依赖时,JVM的重排序可能会导致程序错误,并介绍了如何使用volatile关键字来防止此类问题,确保代码执行的正确顺序。

防止指令重排序

首先看下以下线程A和线程B的部分代码:

线程A:
content = initContent(); //(1)
isInit = true; //(2)

线程B
while (isInit) { //(3)
content.operation(); //(4)
}

从常规的理解来看,上面的代码是不会出问题的,但是JVM可以对它们在不改变数据依赖关系的情况下进行任意排序以提高程序性能(遵循as-if-serial语义,即不管怎么重排序,单线程程序的执行结果不能被改变),而这里所说的数据依赖性仅针对单个处理器中执行的指令序列和单个线程中执行的操作,不同处理器之间和不同线程之间的数据依赖性不会被编译器和处理器考虑,也即是说对于线程A,代码(1)和代码(2)是不存在数据依赖性的,尽管代码(3)依赖于代码(2)的结果,但是由于代码(2)和代码(3)处于不同的线程之间,所以JVM可以不考虑线程B而对线程A中的代码(1)和代码(2)进行重排序,那么假设线程A中被重排序为如下顺序:

线程A:
isInit = true; //(2)
content = initContent(); //(1)

对于线程B,则可能在执行代码(4)时,content并没有被初始化,而造成程序错误。那么应该如何保证绝对的代码(1) happens-before 代码(4)呢?没错,仍然可以使用volatile关键字。
volatile关键字一个重要的作用便是局部阻止重排序的发生,即保证被volatile关键字修饰的变量编译后的顺序,也即是说如果对isInit使用了volatile关键字修饰,那么在线程A中,就能保证绝对的代码(1) happens-before 代码(2),也便不会出现因为重排序而可能造成的异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值