Using AtomicBoolean instead of synchronized blocks

2.3k views Asked by At

Say I have a class with 2 instance variables and the following methods (simplified for this question):

private final Object lock = new Object();
private boolean running;

public MyClass() {
    synchronized(lock) {
        running = false;
    }
}
public void methodA() {
    synchronized(lock) {
        running = true;
    }
}
public void methodB() {
    synchronized(lock) {
        if (!running) {
            return;
        }
    }
}

I was looking at this code, and after reading about AtomicBoolean, I thought that one might fit here, especially after looking at the MyClass constructor and methodA. I wasn't too sure about methodB though.

Assuming these methods could get called by multiple threads, would the following be thread-safe?:

private AtomicBoolean running;

public MyClass() {
    running = new AtomicBoolean(false);
}
public void methodA() {
    running.set(true);
}
public void methodB() {
    if (!running.get()) {
        return;
    }
}

Will running.get() be guaranteed to see an update via running.set(true) or running.set(false) from another thread?

3

There are 3 answers

7
Valette_Renoux On BEST ANSWER

In your example, a simple volatile boolean would be enough, since you only seem to be doing atomic operations. AtomicBoolean is useful if you need the methods such as compareAndSet.

So in answer to your question, yes, when using a volatile boolean or an AtomicBoolean, other threads will see the updates to the variable.

1
Kedar Mhaswade On

Yes. From the Javadoc of AtomicBoolean:

A {@code boolean} value that may be updated atomically.

This means that any update to AtomicBoolean is indivisible. So, I would consider such use of AtomicBoolean to be thread safe.

You should still consider making the declaration of AtomicBoolean final:

private final AtomicBoolean running;

5
AdamSkywalker On

Generally speaking these code blocks are not equal for methodB, because reading volatile variable does not create synchronization order.

Imagine you have some other field int x = 42 in your class, that is updated in methodB:

public void methodB() {
    if (!running.get()) {
        return;
    }
    if (x < 50) x++; // just example
}

Then you have several threads that call methodB:

  • when using synchronized keyword, updates are safe and visible to all threads.
  • when using AtomicBoolean/volatile visibility is broken

If there is no such case with variable updates and the task is just to guarantee visibility between methodA - methodB sequence, then it's OK - AtomicBoolean is enough for that.