开发者社区 问答 正文

谁能真正整明白java volatile 关键字? 一知半解的莫入!

Java代码 收藏代码

/** 
 *  VolatileTest.java 
 * 
 *  Copyright ekupeng,Inc. 2012    
 */  
package test;  
  
/** 
 * @ClassName: VolatileTest 
 * @Description: Volatile测试 
 * @author Emerson emsn1026@gmail.com 
 * @date 2012-11-29 下午06:57:44 
 * @version V1.0 
 *  
 */  
public class VolatileTest extends Thread {  
  
    // 非volatile标志  
    private static boolean flag1 = false;  
    // volatile标志  
    private static volatile boolean flag2 = false;  
  
    private int i = 0;  
  
    public void run() {  
        //Object o = new Object();  
  
        //synchronized (o) {  
            /* 
             * 注释1 
             */  
            while (!flag1) {  
                i++;  
                                //注意 : System.out.println(i);  
                /* 
                 * 注释2 
                 */  
                if (flag2) {  
                    System.out.println("over:" + i);  
                    break;  
                }  
            }  
        //}  
    }  
  
    public static void main(String[] args) {  
  
        VolatileTest t = new VolatileTest();  
        t.start();  
  
        try {  
            Thread.currentThread().sleep(2000);  
            // 先更改flag1  
            t.flag1 = true;  
            /* 
             * 注释3 
             */  
            Thread.currentThread().sleep(1000);  
            // 将flag2置为true,如果有机会进入if(flag2),则将退出循环  
            t.flag2 = true;  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
  
    }  
  
}

因为预览时发现大段的注释会自动换行,影响阅读代码,所以我将代码中的注释提取出来: 注释1 外围标志flag1为非volatile,该线程(t)跑起来后由另一线程(main)将flag1改为true后,如果出现情况1.flag1如果不从主存重新读取,那他将继续以false运行,所以会继续循环并进入内部的flag2的if判断;如果出现情况2.flag1从主存重新读取,那他将以true运行,所以会跳出循环,也就没有机会进入flag2的if判断了; 注释2 如果出现情况1,将进入该判断,内部标志flag2为volatile,当线程(main)将flag2改为true后,因为flag2会从主存重新读取,将以true运行,所以将跳出循环,并打印"over"语句 注释3 为了确保flag1的变更有机会被t察觉,并保证flag2能在flag1变为true后进行一次以上while(!flag1)条件判断后再判断if(flag2),sleep1秒(1秒可以跑很多循环了)

以上是我为了说明volatile的功能写的一段程序,目的是想说一个线程1在循环中通过非volatile的布尔变量来进行条件判断,即使在另一个线程2中修改了该布尔变量,由于该线程1的代码执行得到了某种性能优化,不会从主存重新读取布尔值,导致进入死循环,直到内部的volatile布尔值被改变才跳出。

我的问题是:原本我以为会像预想那样的输出“over”语句,这样也说明了volatile的用处。但是我尝试了Sun JDK1.6,1.5,1.4,1.3,1.2(因为volatile是针对jit带来的优化,所以1.2之前的版本就没有尝试)之后发现只有1.2下才会看到该程序对于volatile的演示效果,输出了“over”语句。其他的都只是在外围的while(!flag1)中实时察觉flag1的变化并跳出了循环。原本以为是hotspot的问题,但是我尝试了hotspot的server或client,以及1.3的classic,都是没有效果的,只有1.2才能看到volatile的演示效果。哪位大神给细说下这个情况?

ps:Object那把锁没有实质的意义,只是进出synchronized块时会重新从主存同步数据,我当时随手写了测了下,所以大家可以不考虑,我暂且将它注掉吧....为了说明这一点,我加了行代码: //注意 : System.out.println(i); 这行代码要是去掉注释,volatile在JDK1.2下也将失去作用,因为System.out.println中含有同步块,一执行该方法,变量将从主存中重新读取。

展开
收起
长安归故里. 2020-01-07 21:15:47 934 分享 版权
1 条回答
写回答
取消 提交回答
  • 以上是我为了说明volatile的功能写的一段程序,目的是想说一个线程1在循环中通过非volatile的布尔变量来进行条件判断,即使在另一个线程2中修改了该布尔变量,由于该线程1的代码执行得到了某种性能优化,不会从主存重新读取布尔值,导致进入死循环,直到内部的volatile布尔值被改变才跳出。 你可能对JMM的理解有偏差。JMM只会说确保一些happen-before。但是对那些非happen-before的情况也不会出现你这种极端情况吧。

    即使在另一个线程2中修改了该布尔变量,由于该线程1的代码执行得到了某种性能优化,不会从主存重新读取布尔值,导致进入死循环。

    多线程编程的问题为什么难以发现,是因为那些非happen-before的代码在大多数情况表现的都是happen-before。如果按你这么说,那些不符合happen-before的问题立马就会出现那就好了。

    2020-01-07 21:15:58
    赞同 展开评论
问答分类:
问答地址: