JIT会优化此代码吗?是否需要同步?

时间:2011-04-13 21:18:16

标签: java thread-safety jit

下面是一个类,其中包含拼写错误的拼写错误地图。通过调用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 个答案:

答案 0 :(得分:3)

您应该使用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不会删除临时地图使用。

答案 1 :(得分:3)

需要同步时需要进行同步。除了兼容的实现符合JLS和Java内存模型并且遵守使用这些规则设计的代码之外,没有任何关于JIT的内容。 (有多种同步方法,并非所有方法都使用synchronized关键字。)

此处需要同步 ,除非看到陈旧版本“没问题”。 (这可能不是这种情况,它可能是一个带有缓存的所有非常陈旧的版本 - 所以不要打赌!)。 “引用的赋值”本身是原子的,因为不会发生“部分写入”,但不能保证在所有线程中[立即]传播(“可见”)。

快乐的编码。