这个变量需要声明为 volatile 吗?
在此代码中,MyThread 类中的 out
变量是否需要声明为 volatile,或者 ThreadTest 类中的 stdout
变量的“波动性”会保留吗?
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();
}
}
}
Does the out
variable in the MyThread class need to be declared volatile in this code or will the "volatility" of the stdout
variable in the ThreadTest class carry over?
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();
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
易失性
限定符不会执行,并且它在上面的代码中没有任何作用。易失性在变量的读写上建立了内存屏障,一旦在构造函数中初始化,就永远不会被修改。出于同样的原因,ThreadTest 中的 volatile 限定符也没有任何作用。需要明确的是,易失性适用于变量,而不是引用的对象。
The
volatile
qualifier won't carry through, and it serves no purpose in the above code. Volatile establishes a memory barrier on reads and writes to the variable, which is never modified once initialised in the constructor. For the same reason, the volatile qualifier inThreadTest
serves no purpose either.Just to be clear, volatile applies to the variable, not to the referenced object.
波动性不会“延续”,因为您实际上传递了变量的值。
根据我对JLS内存模型的阅读 规范,如果您要在创建对象的线程和使用该对象的线程之间没有任何干预同步的情况下读取
out
,则需要易失性
它。在编写的代码中,面临风险的变量是
out
。这是一个非私有变量,可以被任何东西访问/更新可以访问该类。您的示例中没有代码可以执行此操作,但您可以编写另一个类...或更改 ThreadTest。
但在这种情况下,更好的解决方案是:
声明
out
为final
。final
字段的语义 表示不需要同步。将
out
声明为私有
。现在,线程构造和start()
调用之间的“happens-before”确保了对out
唯一可能的访问将看到正确的值。The volatility does not "carry over" because you actually passing the value of the variable.
According to my reading of the JLS memory model spec, a
volatile
is required if you were to readout
without some intervening synchronization between the thread that created the object and the thread that uses it.In the code as written, the variable at risk is
out
. Which is a non-private variable, and could be accesses / updated by anything thathas access to the class. There is no code in your example that does that, but you could write another class ... or change
ThreadTest
.But in this case better solutions would be:
Declare
out
asfinal
. The semantics offinal
fields mean that no synchronization is required.Declare
out
asprivate
. Now the "happens-before" between the thread's construction and thestart()
call ensures that the only possible access toout
will see the right value.肯定不会延续下去。不过,我不确定你想做什么。
volatile
限定 ThreadTest 中的字段,而不是值。It definitely won't carry over. I'm not sure what you're trying to do, though.
volatile
qualifies the field in ThreadTest, not the value.没有必要。
因为之间有happens-before
在调用 Thread.start 之前和调用 Thread.start 之后创建的对象
is not necessary.
Because there is happens-before between
objects that are created before the call Thread.start and after the call Thread.start