>This is a truly fascinating thread of discussion. However, from reading the
>article _The "Double-Checked Locking is Broken" Declaration_
>(http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html)
>
>It seems to me that the following code is thread safe.
>
>if (_jspx_inited == false) {
> synchronized (this) {
> if (_jspx_inited == false) {
> _jspx_init();
> _jspx_inited = true;
> }
> }
>}
This depends on a lot of things. In particular, it depends on whether
_jspx_init() creates any objects as a side-effect. If it does, then this
is just another broken attempt to fix the double-checked lock
problem. (The memory-operation reordering thing is just more complicated
than it looks.)
Not only can a compiler reorder instructions within a synchronized block
(and may also move instructions from outside the block into the block, and
then reorder), but the memory system can make it appear that instructions
are executed out of order unless BOTH threads synchronize on the SAME lock.
If _jspx_init() were to create an object and assign a reference to it
somewhere, then you could still obtain a reference to a partially
constructed object just like with double-checked-locking.
Assuming jspx_init() might create an object (what else would an init()
routine do?), the problem is that your initial reference of jspx_inited is
unsynchronized. Supposed thread A is inside the synchronized
block. Thread B is about to execute "if (_jspx_inited == false). The
compiler/cache/memory CAN make it appear to thread B that jspx_inited has
been set to true before all the instructions corresponding to jspx_init()
have executed.
>In the _jspx_inited case above the only requirement is that compiler can't
>rewrite the code into the equivalent of
>
> _jspx_inited = true;
> _jspx_init();
>
>Such a re-ordering seems illegal to me (what if jspx_init() uses the value
>of _jspx_inited?).
It might seem illegal, but it isn't. They could be executed in the
expected order on one processor, but the memory write corresponding to
jspx_inited might become visible to thread B before the memory writes
generated by jspx_init(), unless the reference to jspx_inited is inside a
synchronized, which it isn't.
But even ignoring memory-system reordering (which you can't) your intuition
is still incorrect. The init() can be inlined, and instructions can be
arbitrarily reordered as long as the compiler/JVM knows that it is not
violating dataflow assumptions (one instruction requires the result of
another) and that the intervening instructions won't throw an exception.
>If, however, it is legal reordering then the example of
>a "correct" double-check mechanism for 32-bit primitive values should work
>here. It would look something like
>
>boolean tmpInited = _jspx_inited;
>if (tmpInited == false) {
> synchronized (this) {
> if (tmpInited == false) {
> tmpInited = _jspx_init(); // NOTE: _jspx_init() needs to
>return true
> _jspx_inited = tmpInited;
> }
> }
>}
Still doesn't fix the problem. jspx_init() can be inlined. Since the
return value (true) doesn't depend on other things done by jspx_init(),
jspx_inited can be set to true (or appear to be so from another thread)
before all the operations of jspx_init() are finished.
What if jspx_init() is defined like this:
public boolean jspx_init() {
foo = InitSomething();
return true;
}
You've still not created a strong enough dataflow requirement to force the
compiler to initialize foo before assigning jspx_inited. And even if you
had, there'd still be the problem of the appearance of reordering because
of caching. The only cure for that is synchronization.
If jspx_init() creates objects or sets any externally accessible value
other than its return value, then you can't make an end-run around the DCL
problem this way.
--
Brian Goetz
Quiotix Corporation
[EMAIL PROTECTED] Tel: 650-843-1300 Fax: 650-324-8032
http://www.quiotix.com
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, email: [EMAIL PROTECTED]