简体   繁体   English

构造了nonFinalField和内部Runnable / Thread可见性

[英]constructed nonFinalField and inner Runnable/Thread visibility

I guess this has to do with a happens-before rule, but I have no concrete explanation ... My question is, if the nonFinalField reference to "Hello World" is guaranteed to be seen by Thread "thread"? 我想这与先前发生的规则有关,但我没有具体的解释......我的问题是,如果对“Hello World”的nonFinalField引用保证被Thread“thread”看到? And no I don't want to make nonFinalField final and it will not be updated later as there is also no method allowing it. 并且我不想让nonFinalField成为最终版本,因为也没有允许它的方法,所以它不会在以后更新。

Hope we can demystify this example with a reasonable explanation. 希望我们能够通过合理的解释揭开这个例子的神秘面纱。

Thank you in advance. 先感谢您。

Kind regards, Hermann 亲切的问候,赫尔曼

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();
    }
}

Yes, the Thread started in startThread is guaranteed to see the value of nonFinalField because starting a thread establishes a "happens before" relationship between the parent (the thread calling main) and child thread (the thread started in startThread ). 是的,在startThread启动的线程可以保证看到nonFinalField的值,因为启动线程会在父线程(线程调用main)和子线程(线程在startThread启动)之间建立“之前发生”关系。

This is listed in the lanuage spec in 17.4.4 (third bullet). 这在17.4.4 (第三个子弹)的语言规范中列出。

As there is no way you can call startThread before the object is constructed (and therefore completely initialises) then this thread will certainly see the non-final field initialised. 由于在构造对象之前无法调用startThread (因此完全初始化),因此该线程肯定会看到初始化的非final字段。

However, if another thread manages to look at it before the thread is run it is possible for the other thread to see an uninitialised field. 但是,如果另一个线程在线程运行之前设法查看它,则另一个线程可能会看到未初始化的字段。

Remember that it is possible to look at private fields through reflection. 请记住,可以通过反射查看私有字段。

From my understanding, it will be visible. 根据我的理解,它将是可见的。 Using the 'happens-before' relationship rules in the java.util.concurrent package javadoc: 使用java.util.concurrent包javadoc中的'happen-before'关系规则:

  • Each action in a thread happens-before every action in that thread that comes later in the program's order. 线程中的每个动作都发生在该线程中的每个动作之前,该动作在程序的顺序中稍后出现。
  • A call to start on a thread happens-before any action in the started thread. 在启动线程中的任何操作之前发生对线程启动的调用。

Since happens-before is transitive, this implies that 'Each action in ThreadA prior to calling ThreadB.start() happens-before every action in ThreadB'. 由于发生之前是传递的,这意味着'在调用ThreadB.start()之前,ThreadA中的每个动作都发生在ThreadB中的每个动作之前。

So if ThreadA is your main thread, and ThreadB is the one you're explicitly creating, then events in the main thread before starting the second thread will be visible. 因此,如果ThreadA是您的主线程,并且ThreadB是您明确创建的线程,那么在启动第二个线程之前主线程中的事件将是可见的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM