javaconcurrencyvolatileatomicboolean

Java Concurrency in Practice 7.2.4


LISTING 7.20. Using a private Executor whose lifetime is bounded by a method call.

public boolean checkMail(Set<String> hosts, long timeout, TimeUnit unit)
            throws InterruptedException {
    ExecutorService exec = Executors.newCachedThreadPool();
    final AtomicBoolean hasNewMail = new AtomicBoolean(false);
    try {
        for (final String host : hosts)
            exec.execute(new Runnable() {
                public void run() {
                    if (checkMail(host))
                        hasNewMail.set(true);
                }
            });
    } finally {
        exec.shutdown();
        exec.awaitTermination(timeout, unit);
    }
    return hasNewMail.get();
}

It is written in the book:

The reason an AtomicBoolean is used instead of a volatile boolean is that in order to access the hasNewMail flag from the inner Runnable, it would have to be final, which would preclude modifying it.

Question: Using the volatile type for the hasNewMail variable here should achieve the same functionality, right? I don't quite understand how this is different from the approach in the book.


Solution

  • No, it won't.

    volatile boolean won’t work here because Java requires that any local variable accessed from within an anonymous inner class must be final or effectively final. Since a primitive boolean is immutable, you can't change its value inside the inner class without violating this rule.

    Since you need to update the flag from multiple threads, that restriction makes volatile unusable here.

    By contrast, AtomicBoolean is a mutable object: you can safely change its internal state from within the inner class even though the reference itself is final.


    To keep in mind: