Reputation: 1202
I have a question about the volatile statement in Java. Please look at this constructed example:
class Master {
// Foo is a class with thread-safe methods
public volatile Foo foo;
}
class Worker1 implements Runnable {
protected Master master
void run() { ... };
}
class Worker2 implements Runnable {
protected Master master
void run() { ... };
}
We have 2 worker threads which hold a reference to an object of class Master running at the same time. During their work, both have to access methods of master.foo. At some point, the Foo object of master will be changed by one of the worker threads. Now my question: Does the use of volatile make the whole construction thread-safe? I am asking this because in a Java tutorial from Oracle it says
However, there are actions you can specify that are atomic:
- Reads and writes are atomic for reference variables [...]
Atomic actions cannot be interleaved, so they can be used without fear of thread interference.
I just would like to make sure that I understood this correctly.
Thanks in advance :)
Upvotes: 3
Views: 5688
Reputation: 38290
volatile is not enough.
I believe this example demonstrates one situation where volatile is not enough:
Shared object:
public class Blammo
{
public String kapow;
}
Code in thread 1:
Blammo blammo = new Blammo();
blammo.kapow = "zowie";
if ((blammo.kapow != null) && (blammo.kapow.isEmpty()))
{
...
}
Code in thread 2:
blammo.kapow = null;
Thread 1 is executing and executes (blammo.kapow != null).
Thread 1 swaps out and Thread 2 swaps in.
Thread 2 executes (blammo.kapow = null).
Thread 2 swaps out and Thread 1 swaps in.
Thread 1 now executes (blammo.kapow.isEmpty()) and throws a null pointer exception.
Upvotes: 3
Reputation: 12283
If the only thing you do is setting this variable, than yes, volatile is enough. As pointed out in the comments, you need volatile to make the changes visible (however, you will not have any corrupt updates without volatile, like you could have with long or double, see below).
By default, reading and writing of reference variables (references to objects) are atomic, as are reading and writing to most primitive types (except for long and double).
With volatile you can make sure that reads and writes to variables of type long and double are also atomic, which you don't need in this case.
So, yes, in this example, it is enough. However, if you're planning on sending more complex messages, consider using tools from java.util.concurrent.*
Upvotes: 1
Reputation: 66876
Reads and writes of references are always atomic in Java, so there is no danger of, for example, seeing the reference in some half-updated state. If this is what you mean by "thread safe" then the operation is thread safe with or without the keyword.
But volatile
is not about atomicity, it affects whether threads can cache writes locally. volatile
would force writes to be written back to main memory and be visible to other threads. If that is what you mean by thread-safe, then yes you need this keyword.
volatile
itself does not affect whether method calls on foo
exclude other threads or not. If that's what you mean you want to use synchronized
, and in a different place.
Upvotes: 10
Reputation: 691635
volatile
ensures that a thread reading the variable will see the new value set in this variable before by another thread. It won't see a stale value stored in a processor cache.
Whether it makes the whole program thread-safe depends on what the program does, how it uses the variable, and how the Foo class is designed.
Upvotes: 4