David, After studying the proposed models in some detail, I return to your
questions and attempt to tease-out some of the implications of these
proposals in terms of real code. [ Experts: Please correct me if I'm
wrong. ]
David Smiley <dsmiley@mitre.org> writes:
> But, there must be /some/ techniques
> [to avoid synchronization] that are okay
> to do. Two that come to mind are:
>
> (1) A latch. If you've got a boolean in a class called
> something like "initialized" that begins being false and
> is eventually true forever... I assume that another thread
> will /eventually/ see that it is initialized in a reasonably
> small amount of time even though there is no explicit
> memory barrier.
>
Disclaimer: I certainly agree with Jeremy's "not necessarily" response and
his advise to use explicit synchronization or declare "initialized" as
volatile.
Nevertheless, according to my reading of the proposed models your assumption
is correct *provided* there is enough "background synchronization" to ensure
transmission.
Specifically, transmission is guaranteed if the initializing thread
subsequently releases a lock or writes to a volatile variable *and* the
reading thread subsequently acquires the same lock or reads the same
volatile variable.
Example, in sequence:
thread 1: initialized = true
thread 1: synchronized(obj) { }
thread 2: synchronized(obj) { }
thread 2: assert(initialized == true)
Note, however, that the order of normal reads and writes is not preserved,
so unless "initialized" is volatile, the reading thread may see "initialized
== true" *before* it sees any other values assigned by the initializing
thread. (The lack of preserved order makes your copy-on-write example even
more vulnerable -- see #2 below.)
Background synchronization can also guarantee the eventual transmission of
unsynchronized "stop" signals in animation loops. Consider Jeremy's
example:
boolean stop = false;
thread 1:
while (!stop) {
// do something
}
thread 2:
stop = true;
If thread 2 subsequently releases a lock or writes to a volatile variable,
and "do something" in thread 1 acquires that same lock or reads that same
volatile variable, then thread 1 must subsequently see "stop == true".
> (2) Copy on write. Again, I assume that another thread
> will /eventually/ see the new reference to whatever was
> replaced in a reasonably small amount of time even
> though there is no explicit memory barrier.
Once again: Declare the object reference volatile or have both threads
access the object reference inside a synchronized block.
Nevertheless, as with #1, the object reference and its contents can be
transmitted by background synchronization. In this case, however, the side
effects of reordering can be even more unexpected.
Example:
Foo foo = new Foo();
Singleton.FOO = foo;
The reference to foo may be transmitted by background synchronization, but,
then again, the reading thread may see the reference to foo before it sees
the initialized contents of foo.
To guarantee that the reading thread will see the initialized contents (if
it ever sees the reference), foo's fields must be declared "final" and/or
its accessor methods must be synchronized.
In the following example, even if a thread sees the new "cell", it is not
guaranteed to see "cell[0] == 1".
int[] cell = { 1 };
Singleton.CELL = cell;
[ Experts: Any mistakes so far? ]
-- Joe Bowbeer------------------------------- JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel
This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:00:31 EDT