2013-09-22 2 views
4

Чтобы доказать безопасность инициализации для неизменяемых объектов, я написал небольшую программу. Несмотря на то, что поля были окончательными, второй поток смог просмотреть полуконструированный объект, создаваемый первым потоком. Есть ли у меня неправильная концепция или «побег объекта» может вызвать ее? Второй поток сначала напечатал «10 null», а затем после половины итераций он начал печатать «10 яблоко».Java гарантирует безопасность инициализации для неизменяемых объектов?

package test; 

import java.util.ArrayList; 
import java.util.List; 

public final class ObjectEscape implements Runnable { 

    private final int a; 
    private final String b; 

    //this list is defined somewhere else 
    public static volatile List<ObjectEscape> globalList = new ArrayList<ObjectEscape>(); 

    public ObjectEscape() throws InterruptedException { 

     a = 10; 
     globalList.add(this); 
     Thread.sleep(10); 
     b = "apple"; 
     System.out.println("done"); 

    } 

    public ObjectEscape(int a) { 
     this.a = 1; 
     b = ""; 
    } 

    public static void main(String are[]) throws InterruptedException{ 

     Thread t = new Thread(new ObjectEscape(1)); 
     t.start(); 
     ObjectEscape oe1 = new ObjectEscape(); 


    } 


    @Override 
    public void run() { 
     int i=0; 
     while(i<10) { 
      if(globalList.get(0) != null) 
      System.out.println(globalList.get(0).a+"  "+globalList.get(0).b); 
     i++; 
     } 
    } 
} 
+1

Коллекция не поточно, и нет никакой гарантии, что поток не будет а) начать долго после добавления объекта или b) закончить задолго до того, как вы добавите объекты. Вы должны помнить, что нить может начать работать и умереть менее чем за 100 микросекунд. –

+0

@PeterLawrey Я полностью согласен, я просто хотел доказать свою точку зрения. Не могли бы вы прокомментировать комментарий, который я сделал на ответ Павла? – Abidi

ответ

8

final поля гарантированно инициализированы , когда вызов завершается застройщик. Естественно, «утечка этого» будет подрывать значение этой гарантии:

globalList.add(this); // ObjectEscape.<init> has not finished yet 

Смотрите также: Java leaking this in constructor

+0

Спасибо, Пол! Другой, но связанный с этим вопрос, поскольку список объявлен volatile, поэтому, как только «this» помещается в список, он будет виден второй поток, правильно? Если да, то верно ли это для состояния «этого», либо оба «а» и «Ь» должны быть определены как летучие, чтобы их сразу видно на второй поток? – Abidi

+1

'volatile' находится в списке. Это означает, что поток увидит ссылку на список просто отлично, но не ** содержимое ** объекта (ов). Запуск 'a' и' b' final достаточно, чтобы убедиться, что все потоки видят правильное состояние при создании объекта (когда возвращается конструктор) –

+0

@PeterLawrey Я думал, что, поскольку список статичен, мне не нужно объявлять его " volatile ", потому что он сконструирован и видим для всех потоков. Вы говорите, что для содержимого списка (в этом примере «этот» объект должен быть видимым для второго потока, он должен быть объявлен изменчивым? – Abidi

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