Java volatile关键字可见性分析

1.背景

计算机具有一定量的主存,用来存储我们程序相关联的数据。当你声明一个变量(例如 flag在我们下面的类中),计算机会留出一个特定的内存位置来保持那个变量的值。大多数CPU能够直接操作主存中的数据。其他CPU只能读取和写入主存位置。这些计算机必须从主存读取数据到寄存器中,在寄存器上操作,然后将数据存储到主存中。然而,即使CPU可以直接在主存中操作数据,通常也有一组寄存器可以保存数据,而寄存器中数据的操作通常比在主存中操作数据快得多。因此,当计算机执行你的代码时,寄存器的使用是非常普遍的。

从逻辑的角度来看,每个线程都有自己的寄存器集。当操作系统将某个线程分配给CPU时,它将CPU寄存器加载到特定于该线程的信息中;在分配给CPU的不同线程之前,它保存寄存器信息。因此,线程从不共享保存在寄存器中的数据。让我们看看这适用于一个java程序。当我们想要终止一个线程时,我们通常使用一个已完成的标志。线程(或Runnable对象)包含代码,如:

2.例子

public void run( ) {
    while (!done) {
        foo( );
    }

}

public void setDone( ) {
    done = true;
}

声明 done变量,将一个特定的内存位置(例如,0xff12345)赋给变量 done 然后设置内存的的值为0(等价于false)

private boolean done=false;

线程1执行 run()方法 ,并将run()编译成一组指令

Begin method run   //开始运行run方法

Load register r1 with memory location 0Xff12345  //将内存 0Xff12345值赋给寄存器r1

Label L1:  //标签 l1锚点

Test if register r1 == 1  //将r1==1比较,此时r1为0

If true branch to L2  //如果为真就跳转到标签l2,即跳出循环

Call method foo    //调用方法foo

Branch to L1      //跳转到标签l1

Label L2:         //标签 l2锚点

End method run   //结束循环

同时,线程2调用setDone(),查看指令:

Begin method setDone  //开始执行setDone方法

Store 1 into memory location 0xff12345   //把1值赋给内存0xff12345 

End method setDone   //结束setDone

你可以看到这个现象:run()方法中r1未从内存(0xff12345)中获取改变的值1。因此,run()从未终止方法

现在我们重新声明done如下:

private volatile boolean done = false;

重新查看下run()方法的指令集:

Begin method run

Label L1: 

Test if memory location 0xff12345 == 1  //注意这里已经直接读取主存中的(0xff12345)内容了!

If true branch to L2

Call method foo

Branch to L1

Label L2:

End method

因此这一次我 们在调用setdone()方法,即可退出循环。
注:java虚拟机可能使用寄存器来处理volatile变量,只要符合volatile可见性的语义!这是一个必须遵守的原则,而不是实际执行的原则。
另外我们可以使用synchronized 关键字来代替volatile,原理是在进入同步边界,会发出信号使寄存器失效,强制从内存重新加载,再退出同步边界时,又会强制从它的局部变量写入内存。

3.volatile误用问题

简单分析,可能由于指令重排问题,非原子性问题造成,恩,下回分析!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值