Ketika mengutak-atik unit test untuk kelas singleton yang sangat bersamaan, saya menemukan perilaku aneh berikut (diuji pada JDK 1.8.0_162):
private static class SingletonClass {
static final SingletonClass INSTANCE = new SingletonClass(0);
final int value;
static SingletonClass getInstance() {
return INSTANCE;
}
SingletonClass(int value) {
this.value = value;
}
}
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
System.out.println(SingletonClass.getInstance().value); // 0
// Change the instance to a new one with value 1
setSingletonInstance(new SingletonClass(1));
System.out.println(SingletonClass.getInstance().value); // 1
// Call getInstance() enough times to trigger JIT optimizations
for(int i=0;i<100_000;++i){
SingletonClass.getInstance();
}
System.out.println(SingletonClass.getInstance().value); // 1
setSingletonInstance(new SingletonClass(2));
System.out.println(SingletonClass.INSTANCE.value); // 2
System.out.println(SingletonClass.getInstance().value); // 1 (2 expected)
}
private static void setSingletonInstance(SingletonClass newInstance) throws NoSuchFieldException, IllegalAccessException {
// Get the INSTANCE field and make it accessible
Field field = SingletonClass.class.getDeclaredField("INSTANCE");
field.setAccessible(true);
// Remove the final modifier
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
// Set new value
field.set(null, newInstance);
}
2 baris terakhir dari metode main () tidak setuju pada nilai INSTANCE - tebakan saya adalah bahwa JIT menyingkirkan metode sepenuhnya karena bidang final statis. Menghapus kata kunci terakhir membuat kode menghasilkan nilai yang benar.
Mengesampingkan simpati Anda (atau ketiadaannya) untuk lajang dan lupa sejenak bahwa menggunakan refleksi seperti ini meminta masalah - apakah asumsi saya benar bahwa optimisasi JIT yang harus disalahkan? Jika demikian - apakah hanya terbatas pada bidang akhir statis?
static final
bidang. Selain itu, tidak masalah apakah retasan refleksi ini rusak karena JIT atau konkurensi.