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

From: Joseph Bowbeer (jozart@csi.com)
Date: Sat Dec 02 2000 - 02:00:10 EST


Do you have a code sample?

Are you just creating a thread or are you starting it, too?

----- Original Message -----
From: "Allen Holub" <allen@holub.com>
To: "Bill Pugh" <pugh@cs.umd.edu>
Cc: <javamemorymodel@cs.umd.edu>
Sent: Friday, December 01, 2000 6:49 PM
Subject: Re: JavaMemoryModel: Race-proof mutable objects and
synchronized constructors

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

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