这个变量是否需要声明为volatile?

时间:2010-05-29 05:28:48

标签: java multithreading volatile

MyThread类中的out变量是否需要在此代码中声明为volatile,或者ThreadTest类中stdout变量的“volatile”是否会延续?

import java.io.PrintStream;

class MyThread implements Runnable
{
    int id;
    PrintStream out; // should this be declared volatile?

    MyThread(int id, PrintStream out) {
        this.id = id;
        this.out = out;
    }

    public void run() {
        try {
            Thread.currentThread().sleep((int)(1000 * Math.random()));
            out.println("Thread " + id);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class ThreadTest
{
    static volatile PrintStream stdout = System.out;

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(new MyThread(i, stdout)).start();
        }
    }
}

4 个答案:

答案 0 :(得分:2)

  

MyThread类中的out变量是否需要在此代码中声明为volatile,或者ThreadTest类中stdout变量的“volatile”是否会延续?

波动性不会“延续”,因为您实际传递了变量的值。

根据我对JLS memory model规范的解读,如果您在创建的主题之间没有介入同步的情况下阅读volatile,则需要out 对象和使用它的线程。

在编写的代码中,风险变量为out。这是一个非私有变量,可以通过任何访问/更新 可以访问该课程。您的示例中没有代码可以执行此操作,但您可以编写另一个类...或更改ThreadTest

但在这种情况下,更好的解决方案是:

  • out声明为finalsemantics of final fields表示不需要同步。

  • out声明为private。现在,线程构造与start()调用之间的“发生前”确保了对out的唯一可能访问权限将会看到正确的值。

答案 1 :(得分:2)

volatile限定符将不会继续执行,并且在上述代码中没有任何用处。 Volatile在对变量的读写操作中建立了内存屏障,一旦在构造函数中初始化,它就永远不会被修改。出于同样的原因,ThreadTest中的volatile限定符也没有任何意义。

为了清楚起见,volatile适用于变量,而不适用于引用的对象。

答案 2 :(得分:0)

绝对不会遗留下来。不过,我不确定你要做什么。 volatile限定ThreadTest中的字段,而不是值。

答案 3 :(得分:0)

没有必要。

因为发生在之前之间 在调用 Thread.start 之前和调用之后创建的对象 Thread.start