First draft of translation document
Brian Goetz
brian.goetz at oracle.com
Wed May 19 10:08:38 PDT 2010
>>> void f() {
>>> shared String s = "hello";
>>> Utils.perhapsRunInAnotherThread(#() {
>>> System.out.println(s); // may or may not prints null
>>> });
>>> }
>>>
>> The initialization of the variable s "happens before" the thread is
>> even created, so there is no race condition. This program always
>> prints "hello". This is no different than if s had been a field.
>>
>
> I am not a concurrency guru but I think you are wrong.
> The field s of the Frame can be printed by another thread before it is
> initialization.
> The local variable s will be correctly initialized but not the
> corresponding field in Frame.
Since 'shared' does not yet exist in the language, we don't know what its
semantics are. Therefore Neal cannot be wrong! (He also cannot be right.)
But lets imagine there was such a language feature, and it had a
specification. Maybe shared variables are implicitly volatile; maybe shared
variables can be declared explicitly volatile in addition to shared.
Reasoning about either case is not so easy. We probably have to assume that
Utils is written such that the closure is not passed from thread to thread via
a data race; that there has to be a happens-before between some point inside
perhapsRunInAnotherThread (call it X) and the execution of the closure body in
the other thread (call it Y).
With this assumption, in both cases there is no data race between the
initialization and the use, since the initialization happens-before X (and by
transitivity, it happens-before the use at Y).
If the assumption fails to hold, making s volatile will generate a
happens-before ordering even if the closure is passed via a data race, but
calls into question other aspects of the closure's internal state (such as the
frame pointer.)
The same argument applies in reverse:
void f() {
shared String s;
Utils.perhapsRunInAnotherThread(#() {
s = "blarg";
});
System.out.println(s);
}
Where we now need a happens-before between the write in the other thread and
the read in the calling thread. Note that this is totally outside the
semantics of closures; it is about the behavior of Utils. So now we find
ourselves reasoning about the JMM characteristics of the dispatch logic in
Utils, which is of course opaque and nearly always underspecified.
Note also that the JSR-292 EG may want to make stronger representations about
whether the various MH combinators behave effectively like setting final
fields in a constructor, or whether the internal state in the combinator nodes
are ordinary nonvolatile mutable state.
More information about the lambda-dev
mailing list