Java 构造的非最终字段和内部可运行/线程可见性
我想这与“先发生后发生”规则有关,但我没有具体的解释。。。 我的问题是,如果非finalfield引用“helloworld”保证被线程“Thread”看到? 不,我不想让nonFinalField成为final,它不会在以后更新,因为也没有允许它的方法 希望我们能用一个合理的解释来揭开这个例子的神秘面纱 先谢谢你 亲切问候,, 赫尔曼Java 构造的非最终字段和内部可运行/线程可见性,java,multithreading,visibility,happens-before,Java,Multithreading,Visibility,Happens Before,我想这与“先发生后发生”规则有关,但我没有具体的解释。。。 我的问题是,如果非finalfield引用“helloworld”保证被线程“Thread”看到? 不,我不想让nonFinalField成为final,它不会在以后更新,因为也没有允许它的方法 希望我们能用一个合理的解释来揭开这个例子的神秘面纱 先谢谢你 亲切问候,, 赫尔曼 由于在构造对象(因此完全初始化)之前无法调用startThread,因此该线程肯定会看到非final字段被初始化 但是,如果另一个线程在运行该线程之前设法查看它
由于在构造对象(因此完全初始化)之前无法调用
startThread
,因此该线程肯定会看到非final字段被初始化
但是,如果另一个线程在运行该线程之前设法查看它,则另一个线程可能会看到未初始化的字段
请记住,可以通过反射查看私有字段。是的,在
startThread
中启动的线程保证可以看到nonFinalField
的值,因为启动线程会在父线程(调用主线程的线程)和子线程之间建立“发生在”的关系(线程在开始线程中启动)
这列在语言规范中(第三个项目符号)。据我所知,它将是可见的。使用java.util.concurrent包javadoc中的“之前发生”关系规则:
- 线程中的每个动作都发生在该线程中的每个动作之前,该线程中的每个动作都是按照程序的顺序稍后出现的
- 对线程的启动调用发生在已启动线程中的任何操作之前
因为before是可传递的,这意味着“ThreadA中调用ThreadB.start()之前的每个操作都发生在ThreadB中的每个操作之前”
因此,如果ThreadA是您的主线程,而ThreadB是您显式创建的线程,那么在启动第二个线程之前,主线程中的事件将可见。构造不会建立“之前发生”的关系。您可以详细说明第二句话吗?@user2050516-例如,如果不使用局部变量,则(正如您在示例中所做的)如果使用对象中的static
变量,则另一个线程很可能会看到static
变量包含尚未初始化的实例变量的对象。
public class Test2 {
private String nonFinalField;
public Test2() {
nonFinalField="Hello World";
}
void startThread() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("nonFinalField: " + nonFinalField);
}
});
thread.start();
}
public static void main(String[] args) {
Test2 test = new Test2();
test.startThread();
}
}