4

To prove initialization safety for immutable objects, I wrote a small program. Even though fields were final, second thread was able to view the half-constructed object being created by the first thread. Have I got the concept wrong or "object escaping" can cause it? Second thread first printed "10 null" and then after half of the iterations it started printing "10 apple".

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++;
        }
    }
}
Abidi
  • 7,846
  • 14
  • 43
  • 65
  • 1
    The collection is not thread safe, and there is no guarantee the thread won't a) start long after you add the object, or b) finish long before you add the objects. You have to remember that a thread can start run and die in less than 100 micro-seconds. – Peter Lawrey Sep 22 '13 at 20:12
  • @PeterLawrey I fully agree, I just wanted to prove my point. Can you please comment on the comment I made on Paul's answer? – Abidi Sep 22 '13 at 20:14

1 Answers1

9

final fields are guaranteed to have been initialized when the contructor call finishes. Naturally, a "leaking this" will subvert the value of this guarantee:

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

See also: Java leaking this in constructor

Community
  • 1
  • 1
Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
  • Thanks Paul! A different but related question, since list is declared volatile so as soon as "this" is put in the list, it will be visible to second thread, correct? If yes, is it true for the state of "this" as well or both "a" and "b" have to be defined volatile to be made immediately visible to second thread? – Abidi Sep 22 '13 at 20:12
  • 1
    the `volatile` is on the List reference. This means the thread will see a reference to the list just fine, but not the **contents** of the object (s). Making `a` and `b` final is enough to ensure all threads see the correct state when the object is created (when the constructor returns) – Peter Lawrey Sep 22 '13 at 20:17
  • @PeterLawrey I thought, since list is static, I don't need to declare it "volatile" because it is constructed and visible to all threads. Are you saying, for the list contents (in this example "this" object) to be visible to second thread, it has to be declared volatile? – Abidi Sep 22 '13 at 20:23
  • @Abidi - actually, the use of the list is not thread-safe, so there are all kinds of problems that could happen. – jtahlborn Sep 22 '13 at 20:25
  • 2
    @Abidi the only way to make the contents of the collection visible is to use locking. Making a reference to a list you don't change volatile won't make any difference. – Peter Lawrey Sep 22 '13 at 20:25
  • 3
    @Abidi - one way to make the list usage safe would be to make the reference final and make the list synchronized (or use a thread-safe implementation). – jtahlborn Sep 22 '13 at 20:26