Мы знаем, что окончание полей - это, как правило, хорошая идея, поскольку мы повышаем безопасность потоков и неизменность, что делает код более удобным для понимания. Мне любопытно, есть ли соответствующая стоимость исполнения.
Модель памяти Java гарантирует это final Field Semantics
:
Поток, который может видеть только ссылку на объект после того, как этот объект был полностью инициализирован, гарантированно увидит правильно инициализированные значения для конечных полей этого объекта.
Это означает, что для такого класса
class X {
X(int a) {
this.a = a;
}
final int a;
static X instance;
}
всякий раз, когда Thread 1 создает экземпляр, подобный этому
X.instance = new X(43);
while (true) doSomethingEventuallyEvictingCache();
и Thread 2 видит его
while (X.instance == null) {
doSomethingEventuallyEvictingCache();
}
System.out.println(X.instance.a);
он должен распечатать 43. Без модификатора final
JIT или CPU могут изменить порядок хранения (сначала сохранить X.instance
, а затем установить a=43
), а Thread 2 может видеть значение, инициализированное по умолчанию, и напечатать 0 вместо этого.
Когда JIT видит final
, он явно воздерживается от переупорядочения. Но это также вынуждает CPU подчиняться приказу. Существует ли связанное с этим ограничение производительности?