tbolender
tbolender

Reputation: 1202

Java: volatile enough to make classes threadsafe?

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

Answers (4)

DwB
DwB

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

scravy
scravy

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

Sean Owen
Sean Owen

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

JB Nizet
JB Nizet

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

Related Questions