JVM дает вам слабые гарантии. Компилятор и оборудование вызывают у вас проблемы. : -)
Когда поток читает переменную, он не обязательно получает последнее значение из памяти. Процессор может вернуть кэшированное значение. Кроме того, даже несмотря на то, что программист создал код, в котором переменная сначала пишется, а затем читается, компилятор может изменить порядок операторов, если он не изменяет семантику программы. Обычно процессоры и компиляторы делают это для оптимизации производительности. В результате поток может не увидеть значения, которые он ожидает увидеть. Это может привести к трудному исправлению ошибок в параллельных программах.
Большинство программистов знакомы с тем фактом, что ввод синхронизированного блока означает получение блокировки на мониторе, которая гарантирует, что никакой другой поток не сможет войти в синхронизированный блок. Менее знакомы, но не менее важны факты, которые
(1) При получении блокировки и вводе синхронизированного блока поток обновляет данные из памяти.
(2) После выхода из синхронизированного блока записанные данные записываются в память.
http://www.javacodegeeks.com/2011/02/java-memory-model-quick-overview-and.html
См. Также JSR 133 (модель памяти Java и редакция спецификации потока) http://jcp.org/en/jsr/detail?id=133 Выпущено с JDK 1.5.