What does volatile guarantee?

R

Roedy Green

Originally I thought volatile just suppressed caching a value in a
register, so that other threads going to RAM would see the latest
value.

IIRC at least in some early JVM, you could not count on 64-bit loads
and stores being atomic.

But on reading the JLS, it seems to guarantee even more. It says all
threads must see a consistent value.

This suggests if your hardware stores a 64-bit long in two 32-bit
stores, it must somehow lock the pair together so that another thread
will not see half the store. I wonder just how they do that, and if
they indeed do.

I don't think the JLS guarantees that a volatile x++ must be atomic.
It appears to be silent on the topic, which I take to mean you can't
count on it.

Any thoughts?
 
R

Roedy Green

I don't think the JLS guarantees that a volatile x++ must be atomic.
It appears to be silent on the topic, which I take to mean you can't
count on it.

Using javap, a volatile long++ looks like this:

0: getstatic #2; //Field key:J
3: lconst_1
4: ladd
5: putstatic #2; //Field key:J

This implies there is no guarantee of atomicity for ++.
 
A

Andreas Leitgeb

No, x++ is indeed *not* guaranteed to be atomic for any "++"-able type.

See AtomicInteger and friends for alternatives (if synchronized not wanted).

but volatile helps in another case:
volatile long x;
thread 1 thread 2
x=0xffffffff;
x=0x100000000L; (x==0xffffffff) || (x==0x100000000L) is true:

/*non-volatile*/ long y;
thread 1 thread 2
y=0xffffffff;
y=0x100000000L; y could also look like 0 or 0x1ffffffffL !!!
 
E

Eric Sosman

Originally I thought volatile just suppressed caching a value in a
register, so that other threads going to RAM would see the latest
value.

IIRC at least in some early JVM, you could not count on 64-bit loads
and stores being atomic.

But on reading the JLS, it seems to guarantee even more. It says all
threads must see a consistent value.

This suggests if your hardware stores a 64-bit long in two 32-bit
stores, it must somehow lock the pair together so that another thread
will not see half the store. I wonder just how they do that, and if
they indeed do.

I don't think the JLS guarantees that a volatile x++ must be atomic.
It appears to be silent on the topic, which I take to mean you can't
count on it.

"Consistent value" is what you're promised, and it's up to
the JVM to deliver it by doing whatever is required.

Your recollection about 64-bit accesses is correct, but it's
a remembrance of things past: Early Java allowed non-atomicity as
a concession to machines that lacked 64-bit atomic operations.
But 64-bit-capable machines are now the norm instead of the
exception, and the rules have been tightened up. (I think this
may have happened as part of the effort to nail down Java's memory
model, which was pretty loosey-goosey in the early days.)

There's no atomicity guarantee for things like x++ or x+=42,
because these are not single accesses: They need paired reads
and writes. The read will be atomic and fetch a consistent
value, the write will be atomic and store a consistent value,
but other (individually atomic) reads and writes may intervene.

Before anybody whines^H^H^H^H^H^Hsuggests that making +=
atomic would be easy, let him ponder

volatile int a,b,c,...,z;
a += b += c+= ... += z;
 
K

Knute Johnson

Originally I thought volatile just suppressed caching a value in a
register, so that other threads going to RAM would see the latest
value.

IIRC at least in some early JVM, you could not count on 64-bit loads
and stores being atomic.

But on reading the JLS, it seems to guarantee even more. It says all
threads must see a consistent value.

This suggests if your hardware stores a 64-bit long in two 32-bit
stores, it must somehow lock the pair together so that another thread
will not see half the store. I wonder just how they do that, and if
they indeed do.

I don't think the JLS guarantees that a volatile x++ must be atomic.
It appears to be silent on the topic, which I take to mean you can't
count on it.

Any thoughts?

From Java Concurrency in Practice by Goetz, "For example the semantics
of volatile are not strong enough to make the increment operation (x++)
atomic, unless you can guarantee that the variable is written only from
a single thread."

The other, and I think most important side effect of volatile is, "The
visibility effects of volatile variables extend beyond the value of the
volatile variable itself. When thread A writes to a volatile variable
and subsequently thread B reads that same variable, the values of ALL
variables that were visible to A prior to writing to the volatile
variable become visible to B after reading the volatile variable" again
from Java Concurrency in Practice.
 
J

Joshua Cranmer

This suggests if your hardware stores a 64-bit long in two 32-bit
stores, it must somehow lock the pair together so that another thread
will not see half the store. I wonder just how they do that, and if
they indeed do.

Well, on Linux x86, it seems that they turn a putfield for a volatile
into (essentially):
volatile julong *p, julong v;
*p = v;

On Linux "zero" (seems to contain at least ARM or PPC), the equivalent
code is "os::atomic_copy64(&v, p);".
I don't think the JLS guarantees that a volatile x++ must be atomic.
It appears to be silent on the topic, which I take to mean you can't
count on it.

volatile only refers to reads and writes to a variable. x++ properly
involves a read, then a copy, then a write, so it is not atomic.
 
L

Lew

Andreas said:
No, x++ is indeed *not* guaranteed to be atomic for any "++"-able type.

If 'x' is volatile, the following guarantees hold for Java 5 and above:

- A write to 'x' establishes /happens-before/ for all prior writes in
that thread (not just to 'x'), and /happens-before/ all subsequent reads
of 'x' from any thread.
- A read from 'x' /happens-before/ all subsequent reads (not just from
'x') in the same thread.
- Therefore all writes in a thread prior to a write in that thread to
'x' /happen-before/ all reads from any thread subsequent to a read from
'x' in that other thread.
- Reads from and writes to 'x' are atomic, whether that variable
represents any primitive including 'long' or 'double', or a reference.

Remarkably, this information is in the JLS (JLSIYF):

<http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.3.1.4>
<http://java.sun.com/docs/books/jls/third_edition/html/memory.html#61803>

As well as in easily findable locations:

<http://www.ibm.com/developerworks/java/library/j-jtp06197.html>

Developerworks is a first choice for researching Java questions, plus GIYF.
 
R

Roedy Green

I have written an entry in the Java glossary merging the points all of
you made. See http://mindprod.com/jgloss/volatile.html

I started on this exercise at the request of student Naheen Dhawan who
asked for clarification on the old volatile entry.

At least it is now clear in my mind. If you can think of better
wording, or see typos, please pass your findings on.
 
L

Lew

Roedy said:
I have written an entry in the Java glossary merging the points all of
you made. See http://mindprod.com/jgloss/volatile.html

I started on this exercise at the request of student Naheen Dhawan who
asked for clarification on the old volatile entry.

At least it is now clear in my mind. If you can think of better
wording, or see typos, please pass your findings on.

The behavior of 'volatile' was significantly different in Java 1.4 and
earlier. It only promised consistently for the volatile variable itself.
Other reads and writes had no guarantees at all. This was before the JLS
introduced the notion of /happens-before/.
 
T

Tom Anderson

I have written an entry in the Java glossary merging the points all of
you made. See http://mindprod.com/jgloss/volatile.html

I started on this exercise at the request of student Naheen Dhawan who
asked for clarification on the old volatile entry.

At least it is now clear in my mind. If you can think of better
wording, or see typos, please pass your findings on.

All i'll add is that what volatile does is somewhat subtle, tying in to
the rest of the memory model, so there isn't a simple way to isolate it in
explanation - but the memory model section in the JLS is really very
good, and people ought to read it. I'd honestly suggest reading that
rather than reading someone else's interpretation of it. Perhaps the most
useful format would be an annotated copy of the JLS text on this matter?

tom
 
L

Lew

Tom said:
All i'll [sic] add is that what volatile does is somewhat subtle, tying in to
the rest of the memory model, so there isn't a simple way to isolate it
in explanation - but the memory model section in the JLS is really very
good, and people ought to read it. I'd honestly suggest reading that
rather than reading someone else's interpretation of it. Perhaps the
most useful format would be an annotated copy of the JLS text on this
matter?

Excellent suggestion. Postgres, for example, has two version of its
docs online - a "static" version with just the official text, and a
"dynamic" version where users (we) can post and read comments.
 
R

Roedy Green

All i'll add is that what volatile does is somewhat subtle, tying in to
the rest of the memory model, so there isn't a simple way to isolate it in
explanation - but the memory model section in the JLS is really very
good, and people ought to read it. I'd honestly suggest reading that
rather than reading someone else's interpretation of it.

see http://mindprod.com/jgloss/volatile.html#LEARNINGMORE

I have added your observation.
 
R

Roedy Green

Excellent suggestion. Postgres, for example, has two version of its
docs online - a "static" version with just the official text, and a
"dynamic" version where users (we) can post and read comments.


What I would like to see a way of combining the official text with
commentary, in a structured way so that you can hide and reveal extra
information. The same mechanism would let you view a text in beginner
mode where all the fine points and difficult sections are suppressed,
or in expert mode, where all the easy stuff is suppressed.

The problem with ordinary commentaries is they go stale and thus
mislead, or they can be simply wrong or oversimplified.

The Wiki model seems to work well, except that it tends to balloon
with trivia.

See http://mindprod.com/jgloss/author.html
 
A

Arne Vajhøj

Your recollection about 64-bit accesses is correct, but it's
a remembrance of things past: Early Java allowed non-atomicity as
a concession to machines that lacked 64-bit atomic operations.
But 64-bit-capable machines are now the norm instead of the
exception, and the rules have been tightened up. (I think this
may have happened as part of the effort to nail down Java's memory
model, which was pretty loosey-goosey in the early days.)

I believe that current JLS still does not guarantee
atomicity of reading/writing long and double.

And even though most CPU's today support 64 bit, then
a lot of them are running in 32 bit mode.

Arne
 
R

Roedy Green

I have written an entry in the Java glossary merging the points all of
you made. See http://mindprod.com/jgloss/volatile.html

I got a report that Firefox under Linux is rendering this page with
all the body text in transparent ink. It works fine with Firefox and
windows. Is anyone else seeing this? It is just volatile.html or
other pages too?

Browsershots will not let me investigate. Somebody else used up
today's quota for mindprod.com

Style sheets and HTML validate ok.
--
Roedy Green Canadian Mind Products
http://mindprod.com

Nothing has really happened until it has been recorded.
~ Virginia Woolf (born: 1882-01-25 died: 1941-03-28 at age: 59)
 
E

Eric Sosman

I believe that current JLS still does not guarantee
atomicity of reading/writing long and double.

See Peter Duniho's reply.
And even though most CPU's today support 64 bit, then
a lot of them are running in 32 bit mode.

The machines I'm familiar with distinguish 32- and 64-bit
"modes" only by the way addresses are generated, handled, and
mapped. 64-bit load and store instructions are available no
matter what the addresses look like, and are atomic (given
proper operand alignment).

YMMV.
 
A

Arne Vajhøj

Arne said:
I believe that current JLS still does not guarantee
atomicity of reading/writing long and double.

Those being primitive types, it does. Lew even described the relevant
"volatile" rule in his earlier reply:
[...]
- Reads from and writes to 'x' are atomic, whether that variable
represents any primitive including 'long' or 'double', or a reference.

Section 17.7 in the JLS states:

<quote>
Some implementations may find it convenient to divide a single write
action on a 64-bit long or double value into two write actions on
adjacent 32 bit values. For efficiency's sake, this behavior is
implementation specific; Java virtual machines are free to perform
writes to long and double values atomically or in two parts.

For the purposes of the Java programming language memory model, a single
write to a non-volatile long or double value is treated as two separate
writes: one to each 32-bit half. This can result in a situation where a
thread sees the first 32 bits of a 64 bit value from one write, and the
second 32 bits from another write. Writes and reads of volatile long and
double values are always atomic. Writes to and reads of references are
always atomic, regardless of whether they are implemented as 32 or 64
bit values.

VM implementors are encouraged to avoid splitting their 64-bit values
where possible. Programmers are encouraged to declare shared 64-bit
values as volatile or synchronize their programs correctly to avoid
possible complications.
<quote>

Lew is talking about volatile long's, which is not what we are
discussing here (volatile long's has been atomic since 1.0).

Arne
 
A

Arne Vajhøj

See Peter Duniho's reply.

See JLS 17.7.
The machines I'm familiar with distinguish 32- and 64-bit
"modes" only by the way addresses are generated, handled, and
mapped. 64-bit load and store instructions are available no
matter what the addresses look like, and are atomic (given
proper operand alignment).

The 32 bit refer to the size of the virtual address. A 32 bit
processor or a 64 bit processor in 32 bit mode can have
instructions that operate on 64 bit entities.

But AFAIK the x86-64 in 32 bit mode does not.

And even though that is just one out of many processors,
then it it is a rather widely used one.

Arne
 
L

Lew

Eric said:
The machines I'm familiar with distinguish 32- and 64-bit
"modes" only by the way addresses are generated, handled, and
mapped. 64-bit load and store instructions are available no
matter what the addresses look like, and are atomic (given
proper operand alignment).

The JLS does not guarantee the atomicity of 'long' and 'double' accesses
absent volatility or other sychronization. /Au contraire/:

<http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.7>
 
L

Lew

Lew is talking about volatile long's, which is not what we are
discussing here (volatile long's has been atomic since 1.0).

Did you read Peter's post? He specifically addressed 'volatile', hence his
use of the word in his post, which is also the subject of this entire thread.
You completely failed to mention that you were deviating from that subject
in your response to Eric to which Peter responded. If you were suddenly to
stop talking about the rules for 'volatile' you should've said so.

Coincidentally, I linked to JLS s. 17.7 at roughly the same time you cited it.
\
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top