Here's a self-contained example executable application that demonstrates that volatile on its own is not enough. Four threads increment a counter 10,000 times each, so you'd expect the counter to be 40,000 at the end. It uses a primitive int variable and an AtomicInt, and tries the exercise 5 times each.
import java.util.Collections; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; class AtomicDemo { interface Demo extends Callable<Void> { int getCounter(); } static class UsePrimitive implements Demo { private volatile int counter = 0; public Void call() throws Exception { for (int i = 1; i <= 10000; ++i) { ++counter; } return null; } public int getCounter() { return counter; } } static class UseAtomic implements Demo { final AtomicInteger counter = new AtomicInteger(0); public Void call() throws Exception { for (int i = 1; i <= 10000; ++i) { counter.incrementAndGet(); System.out.print(""); } return null; } public int getCounter() { return counter.get(); } } public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newFixedThreadPool(4); for (int i = 1; i <= 5; ++i) { Demo demo = new UsePrimitive(); exec.invokeAll(Collections.nCopies(4, demo)); System.out.println("Count to 40000 using primitive, attempt number " + i + ": " + demo.getCounter()); } for (int i = 1; i <= 5; ++i) { Demo demo = new UseAtomic(); exec.invokeAll(Collections.nCopies(4, demo)); System.out.println("Count to 40000 using atomic, attempt number " + i + ": " + demo.getCounter()); } exec.shutdownNow(); } }
Typical output:
Count to 40000 using primitive, attempt number 1: 39711 Count to 40000 using primitive, attempt number 2: 39686 Count to 40000 using primitive, attempt number 3: 39972 Count to 40000 using primitive, attempt number 4: 39840 Count to 40000 using primitive, attempt number 5: 39865 Count to 40000 using atomic, attempt number 1: 40000 Count to 40000 using atomic, attempt number 2: 40000 Count to 40000 using atomic, attempt number 3: 40000 Count to 40000 using atomic, attempt number 4: 40000 Count to 40000 using atomic, attempt number 5: 40000
You see, only with AtomicInt do you always get the expected results.
counter = counter + 1;". Well if you want your counter to have correct values, you should care.