【问题标题】:Volatile Keyword not working as Expected易失性关键字未按预期工作
【发布时间】:2014-06-19 17:35:23
【问题描述】:

我正在学习 volatile 变量。我知道 volatile 的作用,我为 Volatile 变量编写了一个示例程序,但没有按预期工作。

为什么程序会无限循环? 如果变量“isTrue”是易失的,那么它应该总是从主内存中获取值吗?为什么线程要缓存它?

有人能解释一下原因吗?以及是否可以提供解决方案...(我不会将 isTrue 放入 while 循环

我有一个 VolatileSample 类:-

    public class VolatileSample{

static volatile boolean isTrue=true;

public VolatileSample(boolean is){
    isTrue=is;
}

public void print() {
    boolean b=isTrue;
    while (b) {
        System.out.println("In loop!");
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

public void setFalse() {
    boolean b=false;
    System.out.println("Setting value as false");
    isTrue=b;
}

}

创建了两个线程:-

   public class Thread1 extends Thread{

VolatileSample sample;
public Thread1(VolatileSample sample){
    this.sample=sample;
}
public void run(){
    sample.print();
}

} 和

   public class Thread2 extends Thread{

VolatileSample sample;

public Thread2(VolatileSample sample){
    this.sample=sample;
}
public void run(){
    sample.setFalse();
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

}

主类:-

   public class Test {  
public static void main(String[] args) throws InterruptedException {
    // TODO Auto-generated method stub
    VolatileSample sample=new VolatileSample(true);

    Thread1 t1=new Thread1(sample);
    Thread2 t2=new Thread2(sample);

    t1.start();
    t2.start();
}

}

【问题讨论】:

  • 你能解释一下为什么你不想使用 while(isTrue) 吗?

标签: java multithreading volatile


【解决方案1】:

当您应该使用while(isTrue) 时,您在print 方法中使用了while(b)b 是不更新的局部变量,而isTrue 是可以在外部更新的易失变量。这应该有效:

//using this you will understand meaning of volatile
while (isTrue) {
    System.out.println("In loop!");
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

请注意Java is pass by value, not by reference。更新isTrue 字段的值不会直接更新print 方法中b 本地参数的值。如果您不想使用while(isTrue)(很奇怪),那么只需在循环内更新b 的值即可:

while (b) {
    System.out.println("In loop!");
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    //you need to use the volatile variable in order to understand volatile
    b = isTrue;
}

请注意,如果您从不将isTrue 更新为false,则循环将是无限的。让main 方法在延迟延迟后更新字段:

public class Test {

    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        VolatileSample sample=new VolatileSample(true);

        Thread1 t1=new Thread1(sample);
        Thread2 t2=new Thread2(sample);

        t1.start();
        t2.start();
        //naive delay
        Thread.sleep(2500);
        sample.setFalse();
    }
}

您说您不想在while 循环中使用isTrue 变量。然后,在获取其值后,您无法在 print 方法中更新 b 变量。由于此代码中的b 将是true,因此您将有一个无限循环。期间。

您似乎想通过两个线程同步此类,但这不是volatile 字段的重点,因为您使用synchronized 修饰符作为方法或代码片段,正如@JigarJoshi 指出的那样。阅读Simplest and understandable example of volatile keyword in java

你可以有更好的理解

【讨论】:

  • 我告诉过我不会这样做..那么 volatile 的意义何在?
  • @RaghavTandon 您缺少基本的 Java 编程概念:Java 是按值传递,而不是按引用传递。这样就可以了。
  • 感谢好友的回复...我添加了 b = isTrue;但仍在无限循环中..
  • @RaghavTandon 我在您的代码中没有看到您调用VolatileSample#setFalse 的任何部分。如果您从未将isTrue 设置为false,您希望如何停止while 循环?同样,您在基本 Java 方面失败了。
  • @RaghavTandon 不要在 while 循环中使用 isTrue 这将是不可能。你的主要问题是关于 Java 基础知识,而不是理解 volatile,我无法解决这个问题。
【解决方案2】:

您实际上是在将false 设置为局部变量

public void setFalse() {
    boolean b=false; // <-- this is local variable
    System.out.println("Setting value as false");
    isTrue=b; // <-- this is shared but you don't check on it in your while loop
}

不要共享一个

您可能希望通过检查 isTrue 来迭代 while 循环

【讨论】:

  • 好的...感谢您的回复..您能给我一个例子,我实际上可以看到 volatile 关键字工作。我想要一个线程更新和其他从内存读取的例子,如果关键字不是易失性的,那么它应该进入无限循环......
【解决方案3】:

@LuiggiMendoza 是对的:在您了解该语言的基本功能(例如方法调用的工作原理)之前,您不应该尝试理解 volatile

但是如果你坚持...尝试运行它,然后在从timeToStop 声明中取出volatile 关键字后再次尝试。我不能保证在你的操作系统上你的 JVM 会发生什么; Java 语言规范保证当您volatile 时会发生什么。但是,在我操作系统上的 JVM 中,如果变量不是 volatile,则程序永远不会终止。

class Foo {
    private static volatile boolean timeToStop = false;
    private static long count = 0;

    public static void main(String[] argsIgnored) throws InterruptedException {
        Thread busyThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (! timeToStop) {
                    count += 1;
                }
            }
        });
        busyThread.start();
        Thread.sleep(1000);
        timeToStop = true;
        busyThread.join();
        System.out.println(count);
    }
}

【讨论】:

    猜你喜欢
    • 2015-09-09
    • 2017-07-13
    • 2013-07-19
    • 2012-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-26
    • 2021-09-14
    相关资源
    最近更新 更多