Java不能指令重排的情况,java Volatile不能指令重排原因

2Q==

代码的顺序改变后,虽然变量值没有变化,但是对于线程的使用时容易发生不安全的问题。这里也是我们用Volatile时一再说明不能用于重排的原因。下面我们就为大家分析重排导致线程不安全的实例,以及Volatile为了避免这种不安全的情况的发生,所采取的内存屏障的方法。

1.Volatile重排导致线程不安全

对于有些代码进行重排序之后,虽然对变量的值没有造成影响,但有可能会出现线程安全问题的。具体请看下面的代码public class NoVisibility{

private static boolean ready;

private static int number;

private static class Reader extends Thread{

public void run(){

while(!ready){

Thread.yield();

}

System.out.println(number);

}

}

public static void main(String[] args){

new Reader().start();

number = 42;

ready = true;

}

}

这段代码最终打印的一定是42吗?如果没有重排序的话,打印的确实会是42,但如果number = 42和ready = true被进行了重排序,颠倒了顺序,那么就有可能打印出0了,而不是42。(因为number的初始值会是0)。

因此,重排序是有可能导致线程安全问题的。

2.Volatile内存屏障防止重排

Volatile实现禁止指令重排优化,从而避免了多线程环境下程序出现乱序执行的现象。

首先了解一个概念,内存屏障(Memory Barrier)又称内存栅栏,是一个CPU指令,它的作用有两个:

(1)保证特定操作的顺序

(2)保证某些变量的内存可见性(利用该特性实现volatile的内存可见性)

由于编译器和处理器都能执行指令重排的优化,如果在指令间插入一条Memory Barrier则会告诉编译器和CPU,不管什么指令都不能和这条Memory Barrier指令重排序,也就是说 通过插入内存屏障禁止在内存屏障前后的指令执行重排序优化。 内存屏障另外一个作用是刷新出各种CPU的缓存数,因此任何CPU上的线程都能读取到这些数据的最新版本。

在Volatile的写和读的时候,加入屏障,防止出现指令重排,线程安全获得保证。

以上就是java Volatile不能指令重排原因,这也是发挥Volatile内屏障的作用,优势是使用后能够提升整体线程的安全性问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值