> The variable 'first' is /not/ guaranteed to be set to 666. Note that we are
> not talking about the possibility that thread2 might execute before thread1.
[quoted text clipped - 4 lines]
> Roughly speaking, "volatile" is useful only for primitive types[*], everything
> else requires synchronisation.

Signature
Unemployed English Java programmer
http://jroller.com/page/tackline/
>>> Is the non-synchronized method below completely thread safe? I'll
>>> paste it in and then explain each step of my approach:
[quoted text clipped - 27 lines]
> there. The synchronized is irrelevant, as the read is not in a
> synchronized block.
Thank you for these clarifications Thomas. I am primarily interested in
the new memory model since the old memory model has "several serious
flaws" <http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html>.
To reinforce my understanding: If the reference to an array is declared
volatile then different threads accessing array elements through this
volatile reference *will see a consistent view of memory*: "Under the new
memory model, writing to a volatile field has the same memory effect as a
monitor release, and reading from a volatile field has the same memory
effect as a monitor acquire. In effect, because the new memory model
places stricter constraints on reordering of volatile field accesses with
other field accesses, volatile or not, anything that was visible to thread
A when it writes to volatile field f becomes visible to thread B when it
reads f."
Fantastic.
> An easy fix for the old JMM, is to change the values by 1, so that 0
> represents an uninitialised slot. That is always a good strategy.
>
> If we use that fix, then we can ditch the volatile altogether.
Since without the volatile designation another thread could see the
uninitialised array contents of 0 (which is also a cached value!).
Changing the values by 1 to render 0 an uncached value is clearly a good
strategy.
> In the new JMM, reading a volatile is relatively expensive. More
> expensive than writing and almost as expensive as an uncontended lock
> acquisition. Any non-thread local heap values in your registers will
> need to be dropped.
"Effectively, the semantics of volatile have been strengthened
substantially, almost to the level of synchronization. Each read or write
of a volatile field acts like 'half' a synchronization, for purposes of
visibility."
> You should see a further speed up if you move all the slow path code out
> of the method. Try blocks and unnecessary exceptions probably aren't
> going to help either.
Catching an ArrayIndexOutOfBoundsException is part of the slow path. I
understand your advice to move all of the slow path code out of the method
as the fast path is more likely to inlined. But my approach guarantees
that there will be only one array bounds check within the fast path.
With your approach...
> private int[] typeSpecificPos = Const.EMPTY_INT_ARRAY;
>
> public int getTypeSpecificSlotPos(int type) {
> int[] typeSpecificPos = this.typeSpecificPos;
> if (type < typeSpecificPos.length) {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ explicit array bounds check
> int typedPos = typeSpecificPos[type] - 1;
^^^^^^^^^^^^^^^^^^^^^ implicit array bounds check
if (typedPos != -1) {
> return typedPos;
> }
> }
> return getTypeSpecificSlotPosSlowPath(type);
> }
...I have to hope that the runtime will elide the second bounds check upon
typeSpecificPos. Is this an optimisation I should be able to rely upon?
> As always, I have to comment on style: It does not help to have multiple
> statements on one line, multiple declarations on one line, long methods
> or removing spaces.
Yet one of the approaches below uses three times the amount of vertical
real estate. Let's just agree that reasonable people may disagree upon
some matters of style and all be right.
for (int i=oldLen; i<newLen; ++i) {newArray[i]=-1;}
for (int i = oldLen; i < newLen; ++i) {
newArray[i] = -1;
}
Regards,
Adam
Chris Uppal - 27 Mar 2006 12:01 GMT
[I'm just picking up on one point here. See my reply to Thomas for more about
the effects (or not) on array access via a volatile reference.]
> ...I have to hope that the runtime will elide the second bounds check upon
> typeSpecificPos. Is this an optimisation I should be able to rely upon?
Whether it elides it or not, the values used in the comparison are going to be
in L2 cache at worst (or equivalent on other architectures). What with
piplelining, etc, there's a fair chance that the second check will have zero
overhead.
-- chris
Thomas Hawtin - 27 Mar 2006 16:37 GMT
> To reinforce my understanding: If the reference to an array is declared
> volatile then different threads accessing array elements through this
> volatile reference *will see a consistent view of memory*: "Under the new
Well, they need not see any further writes to the array (hence the
necessity to double-check under synchronisation).
> Catching an ArrayIndexOutOfBoundsException is part of the slow path. I
> understand your advice to move all of the slow path code out of the method
> as the fast path is more likely to inlined. But my approach guarantees
> that there will be only one array bounds check within the fast path.
> With your approach...
Array bounds checking is very, very, very cheap. Especially if the
length has already been read.
Perhaps more dubious in terms of performance of my subtracting one
before the comparison. That means the values needs to have arithmetic
performed on it before it can be checked, whereas comparison to zero can
probably be done as part of the load.
You could always measure it.
> Yet one of the approaches below uses three times the amount of vertical
> real estate. Let's just agree that reasonable people may disagree upon
> some matters of style and all be right.
Until it comes to reading someone else's code. Sometimes standards do good.
Tom Hawtin

Signature
Unemployed English Java programmer
http://jroller.com/page/tackline/
Adam Warner - 28 Mar 2006 01:09 GMT
>> To reinforce my understanding: If the reference to an array is declared
>> volatile then different threads accessing array elements through this
[quoted text clipped - 3 lines]
> Well, they need not see any further writes to the array (hence the
> necessity to double-check under synchronisation).
I've just found strong evidence this is correct from the
java.util.concurrent.atomic package:
"The AtomicIntegerArray, AtomicLongArray, and AtomicReferenceArray classes
further extend atomic operation support to arrays of these types. These
classes are also notable in providing volatile access semantics for their
array elements, which is not supported for ordinary arrays."
Doug Lea made this comment about ordinary arrays in August 2003:
<http://www.cs.umd.edu/~pugh/java/memoryModel/archive/1554.html>
"I'd guess that only highly-memory-model-conscious programmers will ever
use these classes, so Hans's and Sarita comments and concerns about
ordinary Java arrays still apply."
Java's memory model remains so weak with respect to volatile arrays that
most programmers will write broken threaded code that only works because
it is running upon an architecture with a strong memory model. Those who
are "highly-memory-model-conscious programmers" will have to suffer the
higher overhead of, say, AtomicReferenceArray which is a generic class
that imposes at least one _extra level of indirection_ upon every element
lookup and a dynamic cast upon every element retrieved because of type
erasure.
Regards,
Adam
[me:]
> > Roughly speaking, "volatile" is useful only for primitive types[*],
> > everything else requires synchronisation.
[quoted text clipped - 4 lines]
> volatile write in the writing thread is visible to any read after the
> volatile read in the reading thread. Clear?
It is undoubtedly time that I gritted my teeth and buckled down to working
properly through JLS3 chap 17. However, from my current sketchy understanding
of the spec, I am not getting that accessing the elements of the array pointed
to by a volatile variable[*] has any specific happens-before relationship
with anything. Do you have a reference (in the JLS or elsewhere) that talks
specifically about that case ? Or maybe you have followed the JLS wording in
more detail than I have. It's a bit odd that the JLS itself doesn't (that I
can find) mention this case at all -- which is particularly strange given that
the change (if real) has rather huge implications.
([*] or other non-volatile value transitively reachable via a volatile
reference.)
BTW, please don't be offended by my doubting you -- I know that you know your
stuff, but this seems to me to be a case were "extraordinary claims require
extraordinary proof" ;-)
-- chris
Thomas Hawtin - 27 Mar 2006 16:23 GMT
> [me:]
>>> Roughly speaking, "volatile" is useful only for primitive types[*],
[quoted text clipped - 14 lines]
> can find) mention this case at all -- which is particularly strange given that
> the change (if real) has rather huge implications.
You are correct for your example, but Adam's example was a bit
different. Reading a volatile reference of an array and then writing to
an element does not force the value to be written out immediately.
In the original example, if a valid value has not been read then it is
always double checked under synchronisation. For that to work, the array
needs to be initialised with an invalid values, -1. In the code the -1
values are written and only after that is the newly created array
written to the volatile. In order to read elements of the array, the
reading thread needs to read the volatile.
Essentially volatiles of any type work to protect data that was local to
the write thread before the volatile was written and does not change
after the write. In Adam's example volatile works to ensure that the
initial zeros are hidden, but other updates rely on the synchronisation.
It's like a one-time synchronise.
[What irritates me a little is that there is apparently no way to do a
plain read of a volatile with the old semantics. You can request a
spurious-failable compare-and-set with the old, through
weakCompareAndSet. But you can't cheaply read the value to be the CAS
on. Not that Sun's JVM implements weakCompareAndSet any differently to
compareAndSet.]
The important part of Chapter 17 is bullet 2 of 17.4.4 (p561) -
"A write to a volatile variable v synchronizes-with all subsequent
reads of v by any thread"
Compare to bullet 1 -
"An unlock action on monitor m synchronizes-with all subsequent
lock actions on m"
Tom Hawtin

Signature
Unemployed English Java programmer
http://jroller.com/page/tackline/