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();
}
}
}
答案 0 :(得分:2)
MyThread类中的out变量是否需要在此代码中声明为volatile,或者ThreadTest类中stdout变量的“volatile”是否会延续?
波动性不会“延续”,因为您实际传递了变量的值。
根据我对JLS memory model规范的解读,如果您在创建的主题之间没有介入同步的情况下阅读volatile
,则需要out
对象和使用它的线程。
在编写的代码中,风险变量为out
。这是一个非私有变量,可以通过任何访问/更新
可以访问该课程。您的示例中没有代码可以执行此操作,但您可以编写另一个类...或更改ThreadTest
。
但在这种情况下,更好的解决方案是:
将out
声明为final
。 semantics of final
fields表示不需要同步。
将out
声明为private
。现在,线程构造与start()
调用之间的“发生前”确保了对out
的唯一可能访问权限将会看到正确的值。
答案 1 :(得分:2)
volatile
限定符将不会继续执行,并且在上述代码中没有任何用处。 Volatile在对变量的读写操作中建立了内存屏障,一旦在构造函数中初始化,它就永远不会被修改。出于同样的原因,ThreadTest
中的volatile限定符也没有任何意义。
为了清楚起见,volatile适用于变量,而不适用于引用的对象。
答案 2 :(得分:0)
绝对不会遗留下来。不过,我不确定你要做什么。 volatile
限定ThreadTest中的字段,而不是值。
答案 3 :(得分:0)
没有必要。
因为发生在之前之间 在调用 Thread.start 之前和调用之后创建的对象 Thread.start