Search code examples
javamultithreadingatomicvolatile

Is AtomicBoolean needed to create a cancellable thread?


I often use the following pattern to create a cancellable thread:

public class CounterLoop implements Runnable {

    private volatile AtomicBoolean cancelPending = new AtomicBoolean(false);

    @Override
    public void run() {
        while (!cancelPending.get()) {
            //count
        }
    }

    public void cancel() {
        cancelPending.set(true);
    }
}

But I'm not sure that cancelPending MUST be a AtomicBoolean. Can we just use a normal boolean in this case?


Solution

  • Using both volatile and AtomicBoolean is unnecessary. If you declare the cancelPending variable as final as follows:

    private final AtomicBoolean cancelPending = new AtomicBoolean(false);
    

    the JLS semantics for final fields mean that synchronization (or volatile) will not be needed. All threads will see the correct value for the cancelPending reference. JLS 17.5 states:

    "An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields."

    ... but there are no such guarantees for normal fields; i.e. not final and not volatile.

    You could also just declare cancelPending as a volatile boolean ... since you don't appear to be using the test-and-set capability of AtomicBoolean.

    However, if you used a non-volatile boolean you would need to use synchronized to ensure that all threads see an up-to-date copy of the cancelPending flag.