Re: JavaMemoryModel: Race-proof mutable objects and synchronized constructors

From: Allen Holub (allen@holub.com)
Date: Fri Dec 01 2000 - 21:49:34 EST


Bill,

One situation I have wrestled with is that of an object that creates a
thread (implemented as an inner class) from within the constructor. The
created (inner-class) object cannot access the creating (outer-class)
object reliably, since there's no memory barrier or synchronization. I've
usually solved this problem by synchronizing the constructor [with a
synchronized(this)] and then having the inner-class constructor synchronize
using synchronized(Outer.this). The problem with this strategy is that the
code that assigns a value to a field that's initialized in the declaration
(which can take an initial value from the outer-class object) is not
included in the synchronized block. On the other hand, it's quite intuitive
how it works---the created thread is effectively suspended until the
creating constructor exits the synchronized block. Your second proposal
seems to solve this access-by-initializer problem, but synchronizing the
constructor seems like a more intuitive solution. Perhaps the best solution
is to support both mechanisms.

Allen

>Say you want to design a class Foo that is designed to work correctly,
>even if references to Foo objects are passed between threads via a data
>race (perhaps maliciously so). Strings are one example of a class we need
>to have be race-proof.
>
>For immutable classes, we have a solution: use final fields. But what
>about for mutable classes?
>
>The standard approach in such cases would be to simply synchronize all of
>the methods of the class, but to not synchronize the constructor.
>Syntactically, it is illegal to declare a constructor as synchronized. You
>could fake it using a synchronized block inside the constructor, but I've
>never seen code that does so.
>
>Unfortunately, to really make the class race-proof, you need to have the
>constructor be synchronized. Without a synchronized constructor, there is
>nothing that forces the processor that initializes the object to send the
>initializing writes from its cache out to main memory.
>
>The JLS states (Section 8.8.3):
>
>"Unlike methods, a constructor cannot be abstract, static, final, native,
>or synchronized.... There is no practical need for a constructor to be
>synchronized, because it would lock the object under construction, which
>is normally not made available to other threads until all constructors for
>the object have completed their work. "
>
>Unfortunately, this is wrong (and has led to some confusion). While there
>is no practical need in constructors for the mutual exclusion semantics of
>synchronization, synchronization also has important visibility semantics
>that are relevant for constructors.
>
>I see two possible solutions:
>
>* Say that in order to bullet-proof the class, you need to use synchronization
> in constructors. You could do this through a synchronized block, but we
> could
> also change the language to allow synchronized constructors.
>
> -- or --
>
>* Give constructors special visibility semantics: when a thread synchronizes
> on an object, it sees all writes that were visible to the constructing
> thread
> at the time the object's constructor terminated. In other words, all
> constructors have the visibility semantics of being synchronized,
> without the
> mutual exclusion semantics of being synchronized. Assuming that you
> don't make
> objects visible to other threads until after they are constructed, this is
> essentially the same as synchronizing all constructors.
>
>Given these choices, I recommend the second option. Although either would
>allow for the creation of race-proof classes, the first option would mean
>that most/all existing synchronized classed would be broken, and I think
>it would be very hard to get most programmers to understand why and when
>constructors need to be synchronized. I don't think choosing the second
>option would require more memory barriers; for a number of reasons, we
>probably already need a memory barrier at the end of each constructor on
>processors with weak memory models.
>
>Thoughts?
>
> Bill
>-------------------------------
>JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel
>

-------------------------------
JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel



This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:00:29 EDT