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.
Answer
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.
Enjoyed this question?
Check out more content on our blog or follow us on social media.
Browse more questions