Подтвердить что ты не робот

Почему хот-спот оптимизирует следующие операции с помощью подъема?

Чтение Эффективная Java, автор упомянул, что

while(!done) i++;

можно оптимизировать по горячей точке в

if (!done) {
    while(true) i++
}

Я очень смущен. сделано обычно не const, почему компилятор может оптимизировать этот путь?

4b9b3361

Ответ 1

Автор предполагает, что переменная done является локальной переменной, которая не имеет каких-либо требований в модели памяти Java, чтобы выставлять ее значение для других потоков без примитивов синхронизации. Или сказал другой способ: значение done не будет изменено или просмотрено каким-либо другим кодом, кроме показанного здесь.

В этом случае, поскольку цикл не меняет значение done, его значение может быть эффективно проигнорировано, и компилятор может поднять оценку этой переменной за пределы цикла, не позволяя ей оцениваться в "горячей" части цикла. Это заставляет цикл работать быстрее, потому что он должен делать меньше работы.

Это также работает в более сложных выражениях, таких как длина массива:

int[] array = new int[10000];
for (int i = 0; i < array.length; ++i) {
    array[i] = Random.nextInt();
}

В этом случае наивная реализация будет оценивать длину массива 10 000 раз, но поскольку массив переменных никогда не назначается и длина массива никогда не изменится, оценка может измениться на:

int[] array = new int[10000];
for (int i = 0, $l = array.length; i < $l; ++i) {
    array[i] = Random.nextInt();
}

Другие оптимизации также применяются здесь, не связанные с подъемом.

Надеюсь, что это поможет.

Ответ 2

Если вы добавите System.out.println("i = " + i); в цикл while. Подъем не будет работать, что означает, что программа останавливается, как ожидалось. Метод println является потокобезопасным, так что jvm не может оптимизировать сегмент кода?

Ответ 3

public class StopThread {
private static boolean stopRequested;

private static synchronized void requestStop() {
    stopRequested = true;
}

private static synchronized boolean stopRequested() {
    return stopRequested;
}

public static void main(String[] args)
                throws InterruptedException {
    Thread backgroundThread = new Thread(new Runnable() {
        public void run() {
            int i = 0;
            while (!stopRequested())
                i++;
        }
    });
    backgroundThread.start();
    TimeUnit.SECONDS.sleep(1);
    requestStop();
}
}

приведенный выше код имеет право в эффективном коде, он эквивалентен использованию volatile для украшения stopRequested.

private static boolean stopRequested() {
  return stopRequested;
}

Если этот метод опускает ключевое слово synchronized, эта программа не работает.
Я думаю, что это изменение вызывает hoisting, когда метод опускает ключевое слово synchronized.