4

Я знаю, что конечные переменные экземпляра публикуются безопасно для всех потоков после завершения конструктора. Тем не менее, я задаюсь вопросом, является ли это еще безопасным, если конечная переменная-экземпляр содержит ссылку на объект, содержащий не конечную переменную-экземпляр. Эта вторичная, не конечная переменная-экземпляр никогда не изменяется после завершения конструктора. Рассмотрим следующий пример:Является ли безопасным публикация конечных переменных экземпляра транзитивным для не заключительных вторичных ссылок?

public class NonFinalImmutable { 
    private Iterable<String> list = Collections.unmodifiableList(Arrays 
      .asList("foo", "bar", "foobar")); 

    public Iterable<String> getList() { 
     return list; 
    } 
} 

public class FinalImmutable { 
    private final NonFinalImmutable reference; 
    private final String[] array; 

    public FinalImmutable(NonFinalImmutable reference, 
      String... arrayEntries) { 
     this.reference = reference; 
     this.array = arrayEntries; 
    } 

    public NonFinalImmutable getReference() { 
     return reference; 
    } 

    public String[] getArray() { 
     return array; 
    } 
} 

private void execute() { 
    new Thread() { 
     @Override 
     public void run() { 
      useLater(construct()); 
     } 
    }.start(); 
} 

private FinalImmutable construct() { 
    return new FinalImmutable(new NonFinalImmutable(), "asdf", "jklö"); 
} 

private void useLater(FinalImmutable finalImmutable) { 
    new Thread() { 
     @Override 
     public void run() { 
      for (String s : finalImmutable.getReference().getList()) { 
       System.out.println(s); 
      } 
      System.out.println(); 
      for (String s : finalImmutable.getArray()) { 
       System.out.println(s); 
      } 
     } 
    }.start(); 
} 

Безопасно ли использовать содержимое экземпляра-переменных FinalImmutable.reference и FinalImmutable.array в другом потоке, даже если они содержат не конечный экземпляр-переменные?

ответ

3

Да, есть действие замораживания, которое возникает при назначении конечных полей. Вы должны прочитать Aleksey Shipilëv's blog, это действительно полезно. Он обсуждает семантику действия замораживания в a 2014 blog entry

И вот как это формально указано. Обратите внимание, что w не может быть записью конечного поля, а r2 не является чтением конечного поля. Что действительно важно, так это то, что подцепка, содержащая действие замораживания F, некоторое действие a и r1, которое читает конечное поле, все вместе делают r2 наблюдаемым w.

Обратите внимание два новых заказы, разыменовывает заказ, и память

В блоге он доказывает, что запись конечного поля происходит до каких-либо действий, которые, в свою очередь происходит до того, как последующее неконечное поле чтения r2.

Также в вашем примере, поскольку вы сначала построили не общий NonFinalImmutable, окончательное назначение должно заморозить записанные ранее записи. Если NonFinalImmutable был доступен снаружи, все ставки отключены.

 Смежные вопросы

  • Нет связанных вопросов^_^