Это из-за модели памяти Java (JMM).
По сути, когда вы объявляете поле объекта как final
, вам нужно инициализировать его в конструкторе объекта, и тогда поле final
не изменит его значение. И JMM обещает, что после завершения ctor любой поток увидит то же (правильное) значение поля final
. Таким образом, вам не нужно будет использовать явную синхронизацию, такую как synchronize
или Lock
, чтобы все потоки могли видеть правильное значение поля final
.
Когда вы объявляете поле объекта как volatile
, значение поля может измениться, но при каждом чтении значения из любого потока будет отображаться последнее записанное значение.
Таким образом, final
и volatile
достигают одной и той же цели - видимость значения поля объекта, но первый специально используется для переменной, может быть назначен только один раз, а второй используется для переменной, которая может изменяться много раз .
Ссылки: