Будет ли JIT оптимизировать этот код? Требуется ли синхронизация? - PullRequest
2 голосов
/ 14 апреля 2011

Ниже приведен класс, в котором содержится карта с ошибками и правильно написанными терминами.Карта периодически обновляется кварцевым заданием, вызывая updateCache ().Метод updatecache обрабатывает ключ и значения во входной карте и сохраняет их во временном объекте карты.После завершения обработки (после цикла for) он назначает временную карту локальной переменной класса misspelledToCorrectlySpelled.

package com.test;

import java.util.HashMap;import java.util.Map;

import org.checkthread.annotations.ThreadSafe;

@ Открытый класс ThreadSafe SpellCorrectListCacheManager {

private Map<String, String> misspelledToCorrectlySpelled = 
    new HashMap<String, String>(0);

/*
 * invoked by a quartz job thread
 */
public void updateCache(Map<String, String> map) {

    Map<String, String> tempMap = new HashMap<String, String>(map.size());

    for (Map.Entry<String, String> entry : map.entrySet()) {
         //process key and values
        String key = entry.getKey().toLowerCase();
        String value = entry.getValue().toLowerCase();

        tempMap.put(key, value);
    }

    // update local variable
    this.misspelledToCorrectlySpelled = tempMap;
}

/*
 * Could be invoked by *multiple* threads
 */
public Map<String, String> getMisspelledToCorrectlySpelled() {
    return misspelledToCorrectlySpelled;
}

}

Вопрос 1 : Оптимизирует ли JIT оптимизацию этого кода?

Фактический код

/*
     * since tempMap is assigned to misspelledToCorrectlySpelled and not
     * used anywhere else, will JIT remove tempMap as shown in the optimized
     * version below?
     */
    Map<String, String> tempMap = new HashMap<String, String>(map.size());

    for (Map.Entry<String, String> entry : map.entrySet()) {
        // process key and values
        String key = entry.getKey().toLowerCase();
        String value = entry.getValue().toLowerCase();

        tempMap.put(key, value);
    }

    this.misspelledToCorrectlySpelled = tempMap;

Оптимизированный код

this.misspelledToCorrectlySpelled = new HashMap<String, String>(map.size());

    for (Map.Entry<String, String> entry : map.entrySet()) {
         //process key and values
        String key = entry.getKey().toLowerCase();
        String value = entry.getValue().toLowerCase();

        this.misspelledToCorrectlySpelled.put(key, value);
    }

Вопрос 2 : Если JIT не оптимизирует код, должен ли синхронизироваться метод getMisspelledToCorrectlySpelled?

/*
     * is this assignment atomic operation?
     * 
     * Does this needs to be synchronized? 
     * 
     * By not synchronizing, the new map may not 
     * be visible to other threads *immediately* -- this is 
     * ok since the new map will be visible after a bit of time 
     * 
     */
    this.misspelledToCorrectlySpelled = tempMap;
}

Ответы [ 2 ]

3 голосов
/ 14 апреля 2011

Синхронизация требуется там, где требуется синхронизация. Ничего в JIT нельзя допустить, за исключением того, что совместимая реализация будет совместима с JLS и моделью памяти Java и будет соответствовать коду, разработанному с этими правилами. (Существует несколько методов синхронизации, но не все используют ключевое слово synchronized.)

Синхронизация требуется здесь, если это не "нормально", что устаревшая версия видна. (Это, вероятно, не тот случай, и это может быть очень устаревшая версия с кешами и всем - так что не на что ставить!). Само «присвоение ссылки» является атомарным, поскольку не может произойти «частичная запись», но не гарантируется, что будет [немедленно] распространен («видим») во всех потоках.

Удачного кодирования.

3 голосов
/ 14 апреля 2011

Вы должны использовать AtomicReference для хранения новой карты, чтобы избежать проблем с синхронизацией и видимостью.Но самая большая проблема в вашем коде состоит в том, что вы предоставляете доступ к не поточнобезопасной изменяемой карте нескольким потокам.Вы должны обернуть вашу карту в неизменяемую карту:

private AtomicReference<Map<String, String>> misspelledToCorrectlySpelled = 
    new AtomicReference<Map<String, String>>(Collections.unmodifiableMap(new HashMap<String, String>(0)));

/*
 * invoked by a quartz job thread
 */
public void updateCache(Map<String, String> map) {

    Map<String, String> tempMap = new HashMap<String, String>(map.size());

    for (Map.Entry<String, String> entry : map.entrySet()) {
         //process key and values
        String key = entry.getKey().toLowerCase();
        String value = entry.getValue().toLowerCase();

        tempMap.put(key, value);
    }

    // update local variable
    this.misspelledToCorrectlySpelled.set(Collections.unmodifiableMap(tempMap));
}

/*
 * Could be invoked by *multiple* threads
 */
public Map<String, String> getMisspelledToCorrectlySpelled() {
    return misspelledToCorrectlySpelled.get();
}

Чтобы ответить на ваш вопрос об оптимизации JIT: нет, JIT не удалит использование временной карты.

...