Here is the code from listing 7.20 in Brian Goetz's Java Concurrency in Practice:
public class CheckForMail {
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();
}
private boolean checkMail(String host) { // Check for mail return
false;
}
}
Referring this code, Goetz says that "The reason an AtomicBoolean is used instead of a volatile boolean is that in order to access the hasMail flag from the inner Runnable, it would have to be final, which would preclude modifying it" (p. 158).
Why does it have to be final? Couldn't you just make it a non-final boolean volatile?
Local variables can't be volatile. If you try to make that change, you'll see it's a compilation error.
Incidentally, as of Java 8, you no longer need to mark the variable as final; as long as it's effectively final (that is, you don't set it after the first time), Java will accept it as if you'd marked it final.