Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java thread accessing outer object before it's created

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?

like image 694
user3363135 Avatar asked Apr 15 '14 08:04

user3363135


People also ask

Can threads access the same object?

Threads will use same object.

When start method is called on thread it enters what state?

Summary: Once a new thread is started, it will always enter the runnable state. The thread scheduler can move a thread back and forth between the runnable state and the running state. For a typical single-processor machine, only one thread can be running at a time, although many threads may be in the runnable state.

Can make thread to go from running to waiting state?

when sleep() is called on thread it goes from running to waiting state and can return to runnable state when sleep time is up.

What happens when you call the Start () method on a thread object?

When we call the start() method on a thread it causes the thread to begin execution and run() method of a thread is called by the Java Virtual Machine(JVM).


2 Answers

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.

like image 88
Raffaele Avatar answered Oct 25 '22 02:10

Raffaele


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.

like image 28
Thomas Avatar answered Oct 25 '22 02:10

Thomas