3

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

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

4 回答 4

2

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

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

根据我对JLS 内存模型规范的阅读,如果您要在创建对象的线程和使用它的线程之间没有一些干预同步的情况下 阅读,volatile 则需要 a 。out

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

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

  • 声明outfinal字段语义final意味着不需要同步。

  • 声明outprivate。现在线程的构造和start()调用之间的“之前发生”确保了唯一可能的访问out将看到正确的值。

于 2010-05-29T05:35:39.577 回答
2

volatile限定符不会通过,并且在上面的代码中没有任何作用。Volatile 在对变量的读取和写入时建立了一个内存屏障,一旦在构造函数中初始化,就永远不会修改。出于同样的原因, volatile 限定符 inThreadTest也没有任何作用。

需要明确的是, volatile 适用于变量,而不是引用的对象。

于 2010-05-29T05:36:01.387 回答
0

它肯定不会延续。不过,我不确定您要做什么。 volatile限定 ThreadTest 中的字段,而不是值。

于 2010-05-29T05:32:53.500 回答
0

没有必要。

因为在调用Thread.start之前和调用Thread.start 之后创建的对象之间存在happens-before

于 2011-07-23T10:12:37.723 回答