This seems a pretty basic issue, but I cannot find a clear confirmation.
Let\'s say I have a class properly synchronized in itself:
public class Sync
This depends entirely on the context of how this variable is shared.
Here is a simple example where it's fine:
class SimpleExample {
private String myData;
public void doSomething() {
myData = "7";
new Thread(() -> {
// REQUIRED to print "7"
// because Thread#start
// mandates happens-before ordering.
System.out.println(myData);
}).start();
}
}
Your given examples may fall under this case. 17.4.5:
If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).
A call to
start()
on a thread happens-before any actions in the started thread.
In other words if the assignment to mySharedObject
takes place on the same thread that starts the new thread, the new thread is mandated to see the assignment regardless of synchronization.
However, if you expect, for example, that init
could be called on a thread that is different from the one that calls doSomething
, then you may have a race condition.
public static void main(String[] args) {
final OuterClass myOuter = new OuterClass();
Thread t1 = new Thread( () -> myOuter.init(true) );
Thread t2 = new Thread( () -> myOuter.doSomething() );
t1.start(); // Does t1#run happen before t2#run? No guarantee.
t2.start(); // t2#run could throw NullPointerException.
}
The fact that SyncClass
has synchronized methods is completely irrelevant with respect to guaranteed state of the mySharedObject
reference. Reading that reference is performed outside the synchronized block.
When in doubt, use final
or volatile
. Whichever is appropriate.