Khi loay hoay với các bài kiểm tra đơn vị cho một lớp singleton có tính đồng thời cao, tôi đã vấp phải hành vi kỳ lạ sau đây (được thử nghiệm trên 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 dòng cuối cùng của phương thức main () không đồng ý với giá trị của INSTANCE - tôi đoán là JIT đã loại bỏ hoàn toàn phương thức này vì trường là tĩnh cuối cùng. Loại bỏ từ khóa cuối cùng làm cho đầu ra mã đúng giá trị.
Bỏ qua sự thông cảm của bạn (hoặc thiếu nó) cho những người độc thân và quên mất một phút rằng sử dụng sự phản chiếu như thế này sẽ gây rắc rối - liệu giả định của tôi có đúng trong sự tối ưu hóa JIT không? Nếu vậy - những cái đó chỉ giới hạn trong các trường cuối cùng tĩnh?
static final
lĩnh vực. Bên cạnh đó, việc hack phản xạ này không thành vấn đề do JIT hoặc đồng thời.