Can volatile be trusted?

D

Daniel

Hi,

After perusing the newsgroups for a good while I have read a number of
disturbing things about the keyword volatile. Among the worst of these
is a statement by "concurrency expert" Bill Pugh that "some JVMs
completely ignore volatile". See:
http://www.cs.umd.edu/~pugh/java/memoryModel/JavaOneBOF/BOF-6up.pdf

However I am not looking for any complex functionality out of volatile
such as atomic operations on long/double variables, etc. I just want
to know if it's generally safe to use volatile in threads in the
following way (on possibly any Java 1.1+ JVM):


class MyThread extends Thread
{
private volatile boolean running = true;

public void stopMe()
{
running = false;
}

public void run()
{
while (running)
{
// Do something useful
}
}
}


I would like to think this always works, because it is very similar to
the method Sun has for stopping a thread on their tutorial. Now I know
Sun's documentation isn't always the most accurate, but for something
as important as ending a thread, you'd like to hope they got it right.

If I can't rely on volatile in this case, what other options do I
have? Syncrhonize ALL access to the variable "running"? This seems
quite inefficient to me, especially if the loop in the run() method
must execute many times very fast.

I'd appreciate any thoughts on the matter. Thanks,

Daniel
 
C

Chris Uppal

Daniel said:
However I am not looking for any complex functionality out of volatile
such as atomic operations on long/double variables, etc. I just want
to know if it's generally safe to use volatile in threads in the
following way (on possibly any Java 1.1+ JVM):

I don't know enough about the details of the various JVM implementations to
give you good advice, but I'd be suspicious of the "volatile" implementations
as early as 1.1.

OTOH, that only matters (and this is a pragmatic decision, after all) if your
Java program is running on a JVM/physical machine that takes advantage of the
loose-coupling of memory accesses allowed by the Java spec. Clearly if the box
has only 1 CPU then there can be no memory synchronisation problems, and
"volatile" is essentially redundant. I also *believe* (and would welcome
corrections) that Intel boxes (and clones) mantain tight memory synchronisation
between CPUs. If that *is* true, then I don't think you'd have a practical
problem on those machines either.

Lastly, even on a loosely coupled machine, my *guess* would be that the change
to "running" (personally, I'd have called it "stopRequested") should propogate
through to other threads in a reasonable time, which might well be all that you
need for your program to function correctly.
If I can't rely on volatile in this case, what other options do I
have? Syncrhonize ALL access to the variable "running"? This seems
quite inefficient to me, especially if the loop in the run() method
must execute many times very fast.

Synchronisation may not be as expensive as you think, it has been a focus of
considerable attention in the recent JVMs from Sun and IBM (and probably all
the other high-performance JVM implementors too). It may be that it wouldn't
cause you any problems (and if it's slow on older implementations, then "slow"
may be better than "faulty" for your purposes). However if the loop is really
very tight, then why not just check the flag every millionth time around the
loop, or something like that ?

-- chris
 
A

Adam Maass

Daniel said:
Hi,

After perusing the newsgroups for a good while I have read a number of
disturbing things about the keyword volatile. Among the worst of these
is a statement by "concurrency expert" Bill Pugh that "some JVMs
completely ignore volatile". See:
http://www.cs.umd.edu/~pugh/java/memoryModel/JavaOneBOF/BOF-6up.pdf

However I am not looking for any complex functionality out of volatile
such as atomic operations on long/double variables, etc. I just want
to know if it's generally safe to use volatile in threads in the
following way (on possibly any Java 1.1+ JVM):


class MyThread extends Thread
{
private volatile boolean running = true;

public void stopMe()
{
running = false;
}

public void run()
{
while (running)
{
// Do something useful
}
}
}


I would like to think this always works, because it is very similar to
the method Sun has for stopping a thread on their tutorial. Now I know
Sun's documentation isn't always the most accurate, but for something
as important as ending a thread, you'd like to hope they got it right.

If I can't rely on volatile in this case, what other options do I
have? Syncrhonize ALL access to the variable "running"? This seems
quite inefficient to me, especially if the loop in the run() method
must execute many times very fast.

I'd appreciate any thoughts on the matter. Thanks,

Short answer: synchronizing both the read and the write of the variable
"running" is guaranteed to work as expected on any compliant VM. Relying on
the volatility of the variable makes getting the correct behavior dependent
on the VM and platform on which the program runs. In the vast majority of
cases, you'll probably see what you expect, but it is not guaranteed.

-- Adam Maass
 
J

John C. Bollinger

Daniel said:
Hi,

After perusing the newsgroups for a good while I have read a number of
disturbing things about the keyword volatile. Among the worst of these
is a statement by "concurrency expert" Bill Pugh that "some JVMs
completely ignore volatile". See:
http://www.cs.umd.edu/~pugh/java/memoryModel/JavaOneBOF/BOF-6up.pdf

However I am not looking for any complex functionality out of volatile
such as atomic operations on long/double variables, etc. I just want
to know if it's generally safe to use volatile in threads in the
following way (on possibly any Java 1.1+ JVM):


class MyThread extends Thread
{
private volatile boolean running = true;

public void stopMe()
{
running = false;
}

public void run()
{
while (running)
{
// Do something useful
}
}
}


I would like to think this always works, because it is very similar to
the method Sun has for stopping a thread on their tutorial. Now I know
Sun's documentation isn't always the most accurate, but for something
as important as ending a thread, you'd like to hope they got it right.

Well, it is quite possible that Sun wrote the docs based on an
assumption of a conforming compiler / JVM. For such a thing, their code
and yours will always work fine.

Here is the relevant text from the Java Language Specification, section
8.3.1.4:
====
A field may be declared volatile, in which case a thread must reconcile
its working copy of the field with the master copy every time it
accesses the variable. Moreover, operations on the master copies of one
or more volatile variables on behalf of a thread are performed by the
main memory in exactly the order that the thread requested.
====

If you can rely on your JVM to comply with the JLS then you are fine;
otherwise, you might want to seek out a better JVM. If you want to take
the route of maximum safety then you will avoid language features that
are not consistently implemented, or that are frequently implemented
incorrectly.
If I can't rely on volatile in this case, what other options do I
have? Syncrhonize ALL access to the variable "running"? This seems
quite inefficient to me, especially if the loop in the run() method
must execute many times very fast.

If you do not use "volatile" then the only thread-safe alternative is to
synchronize all access to shared variables. This may be less expensive
the fewer shared variables you use, but details depend on the JVM.

I think you are best off either assuming that your compiler / JVM
implement the JLS correctly, or avoiding the volatile feature
altogether. Trying to guess exactly how much of the spec for that (or
any) feature you can rely on is playing with fire. If you assume that
it will work, then you would be wise to test on your target platforms.


John Bollinger
(e-mail address removed)
 
R

Roedy Green

Clearly if the box
has only 1 CPU then there can be no memory synchronisation problems, and
"volatile" is essentially redundant.

Volatile has meaning even for single cpu. It inhibits register
caching of a value.
 
J

John C. Bollinger

Roedy said:
Volatile has meaning even for single cpu. It inhibits register
caching of a value.

The Java memory model even permits threads to cache copies of shared
variables in RAM (or, I suppose, in any other storage medium managed by
the VM). This poses a synchronization problem even on one CPU, and
volatile -- if implemented correctly -- effectively inhibits that sort
of caching as well.


John Bollinger
(e-mail address removed)
 
T

Thomas G. Marshall

John C. Bollinger said:
Well, it is quite possible that Sun wrote the docs based on an
assumption of a conforming compiler / JVM. For such a thing, their
code and yours will always work fine.

Here is the relevant text from the Java Language Specification,
section
8.3.1.4:
====
A field may be declared volatile, in which case a thread must
reconcile its working copy of the field with the master copy every
time it accesses the variable. Moreover, operations on the master
copies of one or more volatile variables on behalf of a thread are
performed by the main memory in exactly the order that the thread
requested. ====

If you can rely on your JVM to comply with the JLS then you are fine;
otherwise, you might want to seek out a better JVM. If you want to
take the route of maximum safety then you will avoid language
features that are not consistently implemented, or that are
frequently implemented incorrectly.


If you do not use "volatile" then the only thread-safe alternative is
to synchronize all access to shared variables. This may be less
expensive the fewer shared variables you use, but details depend on
the JVM.

Luckily Java doesn't have the same problem that native languages can, in
that there are often things within a single thread that can get goofed up
without volatile being used.

In a machine where hardware registers are memory mapped, and are used to
direct different behaviors. Sometimes reading can be enough to initiate an
action separate from writing.

int dummy = 0;
char *reg = 0x4662134; // known hardware memory mapped register
dummy = *reg; // read from it to advance printer feed by .1"
dummy = *reg; // do it again: move to .2"
*reg = dummy; // writing to it purges the ink supply

Only one read is performed if dummy is not declared volatile.
 
C

Chris Uppal

The Java memory model even permits threads to cache copies of shared
variables in RAM (or, I suppose, in any other storage medium managed
by the VM). This poses a synchronization problem even on one CPU, and
volatile -- if implemented correctly -- effectively inhibits that sort
of caching as well.

Yes (and, in fact the spec doesn't even mention CPUs, iirc, only threads).
However the OP's issue was not "is this guaranteed to work even if I don't
follow the letter of the spec", but "is this likely to work on old JVMs even if
I *do* follow the letter of the spec". As such it's a pragmatic rather than
theoretical issue. If there are any implementations that do have problems with
memory synchronisation, even on a 1 CPU machine, and which don't respect the
"volatile" flag, then the OP has to consider the possibility that his code will
end up running on those JVMs, if not then it's less of a worry.

In this case, I'm inclined to doubt that there are any such JVMs (but that's
just on the basis that if any commonly used JVM were so badly broken then it
would have been the topic of gossip around here, and on the web), so I may be
wrong. Do you know of any ?

-- chris
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top