19

Yes, this is an academic question, I know people will complain that I'm not posting any code but I'm genuinely struck with this question, really don't know where to begin. I would really appreciate an explanation and maybe some code example.

If an object constructor starts a new thread that executes the method run of an anonymous inner class object, it is possible that this new thread can access its surrounding outer object before it has been fully constructed and its fields fully initialized. How would you prevent this from happening?

Radiodef
  • 37,180
  • 14
  • 90
  • 125
user3363135
  • 370
  • 1
  • 4
  • 12
  • 3
    Any thing you do before a thread is started will be read as you would have expected. Create the thread at the end of the constructor (or preferably have the creator of the object, the caller, start a thread) – Peter Lawrey Apr 15 '14 at 09:49

5 Answers5

20

This is called "leaking this". Here you have the code

public class Test {

  // this is guaranteed to be initialized after the constructor
  private final int val;

  public Test(int v) {
    new Thread(new Runnable() {
      @Override public void run() {
        System.out.println("Val is " + val);
      }
    }).start();
    this.val = v;
  }

}

Guess what it will (may, since it's a thread) print. I used a final field to stress that the object is accessed before it has been fully initialized (final fields must be definitely assigned after the last line of every constructor)

How do you recover

You don't want to pass this around when you are in a constructor. This also mean you don't want to call non-final virtual methods in the very same class (non-static, non-private), and not using inner classes (anonymous classes are inner classes), that are implicitely linked to the enclosing instance, thus it's as they could access this.

Sergio
  • 8,532
  • 11
  • 52
  • 94
Raffaele
  • 20,627
  • 6
  • 47
  • 86
  • 2
    Nice answer, I will upvote if you answer your own question "Guess what it will print." (a random value or 0?) Also I do not get the part "you don't want to call non-final virtual methods in the very same class (non-static, non-private),": could you provide an example of that? – V G Apr 15 '14 at 09:21
  • 1
    @AndreiI it prints 0 or v depending on the thread scheduler. Methods that can be overridden by subclasses (ie non-static non-private non-final) are said to be *virtual* (the JVM dispatches the call at runtime). Since they access the subclass instance, they may run before the child class' constructor. See [this example](http://ideone.com/XnmmuX) – Raffaele Apr 15 '14 at 09:52
10

Think about the single-threaded situation first:

Whenever you create an object via new, its constructor is called which (hopefully) initializes the fields of the new object before a reference to this object is returned. That is, from the point of view of the caller, this new is almost like an atomic operation:

Before calling new, there is no object. After returning from new, the object exists fully initialized.

So all is good.


The situation changes slightly when multiple threads come into play. But we have to read your quote carefully:

...has been fully constructed and its fields fully initialized.

The crucial point is fully. The subject line of your question says "before created", but what is meant here is not before the object has been created, but between object creation and initialization. In a multi-threaded situation, new can no longer be considered (pseudo-)atomic because of this (time flows from left to right):

Thread1 --> create object --> initialize object --> return from `new`
                           ^
                           |
                           | (messing with the object)
Thread2 ------------------/

So how can Thread2 mess with the object? It would need a reference to that object but since new will only return the object after is both been created and initialized, this should be impossible, right?

Well, no - there is one way where it's still possible -- namely if Thread 2 is created inside the object's constructor. Then the situation would be like this:

Thread1 --> create object --> create Thread2 --> initialize object --> return from `new`
                                      |       ^
                                      |       |
                                      |       | (messing with the object)
                                       \-----/

Since Thread2 is created after the object has been created (but before it has been fully initialized), there is already a reference to the object that Thread2 could get a hold of. One way is simply if the constructor of Thread2 explicitly takes a reference to the object as a parameter. Another way is by using a non-static inner class of the object for Thread2's run method.

Thomas
  • 17,016
  • 4
  • 46
  • 70
  • But non of the ways is really safe, as long as your class is not final! Since your constructor could be called as "super()" from a child-class and you would access the methods of this child before it is fully constructed... – Falco Apr 15 '14 at 09:19
  • And this is one of the reasons why you should never call setVisible(true) inside of the constructor of a SwingUI Object which is not called on the EventPump Thread... – Falco Apr 15 '14 at 09:21
  • You forgot to answer the question: "How do you prevent this...?" – V G Apr 15 '14 at 09:23
  • @Andrei That's right, actually :-) But I guess it's kind of implicit: don't do what is described in my answer, or at least be aware of the risks. – Thomas Apr 15 '14 at 09:29
  • @Falco Inheritance is a whole other issue -- my answer concentrates on how it would be possible to interfere with an object "from outside", between its creation and its initialization. – Thomas Apr 15 '14 at 09:30
  • @Thomas IMHO there are different possibilities: not to pass `this` to threads in the constructor, or do not use inner classes for threads or instantiate them after after initializing (using synchronization of course). – V G Apr 15 '14 at 09:32
2

I do not fully agree with Pablos answer because it heavily depends on your initialization method.

public class ThreadQuestion {

    public volatile int number = 0;

    public static void main(String[] args) {
        ThreadQuestion q = new ThreadQuestion();
    }

    public ThreadQuestion() {
        Thread t = new Thread(new Runnable() {

        @Override
        public void run() {
            System.out.println(number);             
        }
        });

        try {
        Thread.sleep(500);
        } catch(Exception e) {
            e.printStackTrace();
        }
        number = 1;     
        t.start();
    }
}

When you

  1. place t.start() at the end, the correct data is printed.
  2. place t.start() before the sleep command, it will print 0
  3. remove the sleep command and place t.start() before the assignment it can print 1 (not determinable)

Play a mind game on 3.) you can say a "tiny" assignment of 1 simple data type will work as expected but if you create a database connection it will not achieve a reliable result.

Do not hesitate to raise any question.

Markus
  • 763
  • 7
  • 24
  • It is possible but doesn't necessarily happens. You just have to change the sleep time and, more generally, the code in between the attrubutes initialization and thread start – Pablo Francisco Pérez Hidalgo Apr 15 '14 at 08:52
  • I tried to highlight that some outcomes are **not determinable**. The initial question let's a lot of open points in which direction we should dig further. – Markus Apr 15 '14 at 08:53
  • You can guarantee it won't happen if thread's `start` method is the last line of the constructor. – Pablo Francisco Pérez Hidalgo Apr 15 '14 at 08:55
  • There is no guarantee whatsoever here - none of your 3 scenarios are determinate. The compiler can reorder these statements in any way it wants, provided the thread that's running the statements won't notice the difference (and in this case, it won't). And when using a non-volatile variable you have no guarantee when (or even if!) writing number=1 becomes visible to other threads. In short, you got lucky. – Chris Hayes Apr 15 '14 at 16:54
  • @ChrisHayes Thank you for your input. I extended the code snippet by the keyword volatile. Do you mind changing my example in order to make it work? – Markus Apr 15 '14 at 17:02
2

I would change the title of the question, as threads are not accessing themselves, but the second one to the first one. I mean: You have one thread, creating an object. Inside the constructor for this object, you declare an anonymous inner class that implements Runnable. In the same constructor of the first thread, you start a new thread to run your anonymous inner class. Thus, you're having two threads. If you want to assure that the new thread doesn't do anything before the constructor is "fully ended", I would use some locks in the constructor. This way, the 2nd thread can be started but will wait until the first thread ends.

public class A {
    int final number;

    A() {
        new Thread(
            new Runnable() {
                public void run() {
                    System.out.pritnln("Number: " + number);
                }
        }).start();
    number = 2;
    }
}
JavierV
  • 396
  • 1
  • 4
1

So a situation like this?

public class MyClass  {
    private Object something;
    public MyClass() {
        new Thread() {
            public void run() {
                something = new Object();
            }
        }.start();
    }
}

Depending on the actual code used, the behaviour could vary. This is why constructors should be carefully made so that they don't for example call non-private methods (a subclass could override it, allowing the superclass this to be accessed from a subclass before the superclass is fully initialized). Although this particular example deals with a single class and a thread, it's related to the reference leaking problem.

Kayaman
  • 72,141
  • 5
  • 83
  • 121