Различное поведение, выполняемое и отлаживающее программу Java, Eclipse

У меня есть этот код (отложите в сторону его целесообразность на данный момент):

    Class<?> cacheClass = Class.forName("java.lang.Integer$IntegerCache");
    Field cacheField = cacheClass.getDeclaredField("cache");
    cacheField.setAccessible(true);
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(cacheField, cacheField.getModifiers() & ~Modifier.FINAL);

    Integer betterCache[] = new Integer[255];
    for (int i = 0; i < betterCache.length; i++) {
        betterCache[i] = 20;
    }
    cacheField.set(null,  betterCache);
    System.out.println(10);
    System.out.println((Integer) 10);

Я ожидаю, что второй println будет печатать 20, поскольку я заменил кешированный Integers на 20. Когда я отлаживаю программу в Eclipse, она делает то, что я ожидаю, она получает значение из кеша и печатает 20, тогда как она печатает 10 в обоих случаях, когда я просто запускаю его либо из IDE, либо путем вызова java. Как объяснить это поведение?

UPD: Он работает таким образом, если скомпилирован с 1.8 javac. Он печатает 10 и 20, если скомпилирован с версией 1.6.

Ответы

Ответ 1

Это определенно вызвано компилятором Just in Time. Вы должны добавить -XX: + PrintCompilation в JVM-параметры, это также более заметно, если вы выполните итерацию

System.out.println((Integer) 10);

много раз. Вы заметите, что компиляция

java.lang.Integer::valueOf (32 bytes)

и

java.nio.ByteBuffer::arrayOffset (35 bytes) 

влияет на результат.

Ответ 2

ИЗМЕНИТЬ

Я был совершенно не прав

Определенно, вы играете с огнем, с моей точки зрения, это для условий гонки (небезопасная нить в java 8). Если вы проверите это:

    Class<?> cacheClass = Class.forName("java.lang.Integer$IntegerCache");
    Field cacheField = cacheClass.getDeclaredField("cache");
    cacheField.setAccessible(true);
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(cacheField, cacheField.getModifiers() & ~Modifier.FINAL);
    Integer firstCache[] = (Integer[])cacheField.get(null);
    Integer betterCache[] = new Integer[255];
    for (int i = 0; i < betterCache.length; i++) {
        betterCache[i] = 20;
    }
    System.out.println(firstCache == betterCache);
    cacheField.set(null, betterCache);
    System.out.println(10);
    for (int i = 0; i < 1000000; i++) {
        System.out.println((Integer) 10);     
    }

Вы увидите ожог Java.