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++;
        }
    }
}
2
  • 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. Commented Sep 22, 2013 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? Commented Sep 22, 2013 at 20:14

1 Answer 1

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

Sign up to request clarification or add additional context in comments.

6 Comments

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?
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)
@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 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.
@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).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.