Построенный nonFinalField и внутренняя Runnable/Thread видимость

Я предполагаю, что это связано с правилом "происходит раньше", но у меня нет конкретного объяснения... Мой вопрос заключается в том, гарантированно ли нить ссылку на "Hello World" потоком "поток"? И нет, я не хочу делать окончательный вариант nonFinalField, и он не будет обновляться позже, так как нет способа, позволяющего это сделать.

Надеюсь, мы сможем демистифицировать этот пример с разумным объяснением.

Заранее спасибо.

С уважением, Герман

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

3 ответа

Решение

Да, Тема началась в startThread гарантированно увидеть значение nonFinalField потому что запуск потока устанавливает отношение "происходит раньше" между родителем (поток, вызывающий main) и дочерним потоком (поток запущен в startThread).

Это указано в спецификации языка в 17.4.4 (третья пуля).

Как нет возможности позвонить startThread до того, как объект будет создан (и, следовательно, полностью инициализирован), этот поток непременно увидит инициализированное неконечное поле.

Однако, если другому потоку удается просмотреть его до запуска потока, другой поток может увидеть неинициализированное поле.

Помните, что на частные поля можно смотреть через отражение.

Насколько я понимаю, это будет видно. Используя правила отношений "происходит до" в пакете java.util.concurrent javadoc:

  • Каждое действие в потоке происходит перед каждым действием в этом потоке, которое происходит позже в порядке программы.
  • Вызов для запуска в потоке происходит до любого действия в запущенном потоке.

Поскольку случившееся до является транзитивным, это означает, что "Каждое действие в ThreadA перед вызовом ThreadB.start() происходит перед каждым действием в ThreadB".

Так что, если ThreadA - это ваш основной поток, а ThreadB - это тот, который вы явно создаете, то события в основном потоке перед запуском второго потока будут видны.

Другие вопросы по тегам