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?
Threads will use same object.
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.
when sleep() is called on thread it goes from running to waiting state and can return to runnable state when sleep time is up.
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).
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
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With