Re: how to make this code thread safer?
Peter Duniho wrote:
The first mechanism has to do with semantics surrounding object
construction. In .NET, the specification ensures that whatever happens
in the constructor "happens before" any other code that uses the
reference after the constructor completes (.NET doesn't actually use the
term "happens-before", but it's the same idea). I would expect Java to
be the same in this respect.
I'm pretty sure it's not the same in Java. The semantics of the
constructor only guarantee that an object will be visible to the calling
thread. All other threads may not see a completely and correctly
constructed object. And I'd be surprised if it's any different in C#,
because that would imply a memory barrier at every object construction,
although I guess C# could indeed be doing such a thing.
In the case of the EDT, the typical way an object reference would get
from another thread to the EDT is via the invokeLater() or
invokeAndWait() methods. These methods are inherently synchronized
themselves; it's a natural consequence of what must happen for the data
passed to the methods to get to the EDT.
I agree that the only practical way to pass an object to the EDT
involves a shared lock. However, invokeLater() makes no such guarantee,
and they'd be within their rights to change their implementation of
invokeLater() and remove any shared locks, thus removing any
synchronization and any happens-before semantics. Contrast this with
the docs of some of the concurrent classes like Executor, which does
provide an explicit memory consistency guarantee.
Thus, I think the minimum you can get away with is a volatile field:
public class Main {
public static void main( String... args ) {
final MyClass test = new MyClass();
SwingUtilities.invokeLater( new Runnable() {
private volatile MyClass temp = test;
public void run() {
MyClass model = temp;
... // ok to use model now...
}
} );
}
}
This applies more generally to any cross-thread communication mechanism.
Even if not using the EDT, there is likely some synchronized
data-transfer mechanism that acts as the go-between, allowing that newly
constructed reference to safely move from one thread to the other.
This is an even scarier assertion, imo. I don't agree that we should
rely on what's "likely" to happen in concurrency, unless you only want
it "likely" that your program will run correctly.