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

From: Tom May (tom@go2net.com)
Date: Fri Dec 01 2000 - 22:15:13 EST


Bill Pugh <pugh@cs.umd.edu> writes:

> 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.

Did I miss something? It seems that even with a synchronized
constructor, the write to the shared reference could be written to
main memory before the object's contents. That's ok if, as you say,
all the methods are synchronized. However, I think you would also
need the (synchronized) constructor to have mutual exclusion
characteristics, contrary to what you suggest below in the second
option, to ensure a second thread could only synchronized after the
constructor has completed.

> 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).

Yes, I've wondered what they were really thinking when they wrote that.

> 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.

Including the semantics of what is visible to the constructor? It's
not obvious to me whether that's necessary/useful or not.

> 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.

If the second option falls out of some other need for memory barriers,
then it's ok, modulo the mutual exclusion concerns. Otherwise I would
go with the first option so as not to sacrifice single-threaded
performance -- unless the rest of the changes to the JMM make it very
easy for most programmers to know what should be synchronized, but
knowing when to synchronize constructors would still be difficult for
most programmers.

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

Tom.
-------------------------------
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