在java中使用volatile关键字时获取错误的值

时间:2013-08-02 07:15:26

标签: java

我对volatile关键字的行为有疑问。

public class TestClassI extends Thread {

    private volatile int i=5;
    boolean flag;
    public TestClassI( boolean flag) {
        this.i=i;
        this.flag=flag;
    }   
    public void run()
    {
        if(flag)
        {
            while(true)
            {
                System.out.println(i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        else
        {
            i=10;
        }
    }
}

在主要课程中使用as

public class TestMain {

    public static volatile int i=5;
    public static void main(String args[]) throws InterruptedException
    {

        TestClassI test= new TestClassI( true);
        test.start();
        Thread.sleep(1000);

        TestClassI test2=new TestClassI( false);        
        test2.start();
    }
}

我预计价值会是这样的 五 五 五 五 10 10 10 10。 但是它继续给出5.但是每次我应该从主存储器中存储和检索i的易变性值的asper性质。请解释这段代码有什么问题吗?

4 个答案:

答案 0 :(得分:3)

您有两个TestClassI个实例。它们各自都有自己的i版本(因为它是一个实例字段)。它们完全不会干扰彼此。

程序中根本没有使用静态TestMain.i。没有共享状态。

答案 1 :(得分:0)

当使用false标志对象进行实例化时,run方法将i初始化为10,然后返回。永远不会打印i

if (flag) {
    // irrelevant
}
else {
    i = 10;
}

答案 2 :(得分:0)

您没有在循环中设置i=10,因此它将被设置为您帖子中的唯一操作,但从不打印...

答案 3 :(得分:-2)

volatile变量在这种情况下无效,因为变量是intlongdouble变量受volatile影响,它们被加载并存储在一个操作中,该操作不能被中断而不是两个,每个单词一个。所以volatile变量没有效果。

产生异常输出的情况是,i不会在您的线程之间共享。如果你看,每个线程都有一个单独的i,尽管主类中有一个静态i。仅供参考,主要类中的i没有被线程忽视,他们根本没有注意到它。如果你想让它工作,一个简单的修改就足够了:让线程中的i变量保持静态。不在主类中,在线程中。