2010-05-29 56 views
3

MyThread类中的out变量是否需要在此代码中声明为volatile?或者ThreadTest类中stdout变量的“volatile”是否会延续?这个变量是否需要声明为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(); 
     } 
    } 
}

回答

2

volatile限定符不会贯彻,它在上述代码中没有任何用处。易失性在读取和写入变量时建立内存屏障,在构造函数中初始化后永远不会修改该变量。出于同样的原因,ThreadTest中的挥发性限定符也没有任何作用。

只是要清楚,挥发性适用于变量,而不是引用的对象。

+1

嗯......我的JLS的内存模型阅读规范是,在构造函数中写入(非易失性,非最终)字段并在另一个线程中读取它之间不存在“发生之前”关系。这样就可以在示例中使'volatile'限定符不是冗余的。 – 2010-05-29 06:23:36

+0

@Stephen C,在构造函数返回之前,另一个线程不可能访问该变量。 – 2010-05-29 06:36:13

+1

除非对象被构造函数“不安全地发布”(这里不是这种情况)。但是在这里我们正在讨论在构造函数返回后访问变量的另一个线程;即在“运行”方法中。 – 2010-05-29 06:43:03

0

它绝对不会结转。不过,我不确定你想要做什么。 volatile限定了ThreadTest中的字段,而不是值。

2

MyThread类中的out变量是否需要在此代码中声明为volatile?还是将ThreadTest类中的stdout变量的“volatile”包含在内?

由于您确实传递了变量的值,所以波动率不会“结转”。

根据我的JLS memory model规范的读数,volatile如果你读out没有创建该对象的线程和使用它的线程之间的一些中介同步需要

在所写的代码中,处于风险的变量为out。这是一个非私有变量,可以通过 有权访问的任何内容访问/更新。你的例子中没有这样的代码,但你可以写另一个类......或者更改ThreadTest

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

  • 声明outfinalsemantics of final fields表示不需要同步。

  • 声明outprivate。现在,线程结构和start()呼叫之间的“发生 - 之前”确保只有通过out才能看到正确的值。

0

没有必要。

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

相关问题