เมื่อเล่นซอกับการทดสอบหน่วยสำหรับคลาสซิงเกิลตันที่เกิดขึ้นพร้อมกันสูงฉันสะดุดกับพฤติกรรมแปลก ๆ ต่อไปนี้ (ทดสอบบน 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 บรรทัดสุดท้ายของเมธอด main () ไม่เห็นด้วยกับค่า INSTANCE - ฉันเดาว่า JIT กำจัดวิธีการอย่างสมบูรณ์เนื่องจากฟิลด์เป็นแบบสแตติกสุดท้าย การลบคำหลักสุดท้ายทำให้รหัสถูกต้องค่าผลลัพธ์
ออกจากความเห็นอกเห็นใจของคุณ (หรือขาดมัน) สำหรับซิงเกิลตันและลืมไปหนึ่งนาทีว่าการใช้การสะท้อนเช่นนี้เป็นการถามปัญหา - สมมติฐานของฉันถูกต้องในการเพิ่มประสิทธิภาพของ JIT หรือไม่ ถ้าเป็นเช่นนั้น - จะถูก จำกัด เฉพาะเขตข้อมูลสุดท้ายคงที่เท่านั้น?
static final
ฟิลด์ นอกจากนั้นมันไม่สำคัญว่าแฮ็คการสะท้อนนี้จะแตกเนื่องจาก JIT หรือการทำงานพร้อมกัน