Java多线程/并发09、浅谈volatile

首先声明:现在JVM经过优化,已不会出现liveness failure 。所以没事别用volatile。

在了解volatile之前,先介绍一个名词:liveness failure ,直译叫作活性失败。因为这是volatile很重要的一个应用场景:

public class volatileDemo {
    private static boolean stopFlag;
    public static void main(String[] args) throws InterruptedException {
        Thread volatileThread =new Thread(){
            @Override
            public void run() {
                while(!stopFlag){
                    System.out.print(Calendar.getInstance().get(Calendar.SECOND)+",");
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        volatileThread.start();
        Thread.sleep(3000);
        stopFlag=true;
    }
}

运行几秒钟之后,发现并没有终止输出。(jre1.7之前会出现)
主线程修改了变量stopFlag,子线程B却没有感知,称为活性失败。

Java内存模型(JMM)规定了所有的变量都存储在主内存中,主内存中的变量为共享变量,而每条线程都有自己的工作内存,线程的工作内存保存了从主内存拷贝的变量,所有对变量的操作都在自己的工作内存中进行,完成后再刷新到主内存中。
这里写图片描述

代码stopFlag=true;主线程(线程main)虽然对stopFlag的变量进行了修改且刷新回主内存中(《深入理解java虚拟机》中关于主内存与工作内存的交互协议提到变量在工作内存中改变后必须将该变化同步回主内存),但volatileThread线程读的仍是自己工作内存的旧值导致出现多线程的可见性问题,解决办法就是给stopFlag变量加上volatile关键字。

据effective Java中描述,这个问题涉及到JVM对while(!flag)这种形式有一个提升的优化,即:

while(!flag){}

进行提升优化:

if(flag){
    while(true){}
}

重点参考文章:
http://www.ibm.com/developerworks/cn/java/j-jtp06197.html
http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html

总结如下

  1. volatile重要工作是避免线程脏读:当线程对volatile变量进行读操作时,会先将自己工作内存中的变量置为无效,之后再通过主内存拷贝新值到工作内存中使用。
  2. volatile解决的是变量在多个线程之间的可见性,但不能完全保证数据的原子性。
  3. 现在JVM经过优化,已不会出现liveness failure 。所以没事别用volatile。
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值