public class Generator {
private static final Map<byte[], byte[]> cache = new HashMap<byte[], byte[]>();
public static byte[] generate(byte[] src) {
byte[] generated = cache.get(src);
if (generated == null) {
synchronized (cache) {
generated = cache.get(src);
if (generated == null) {
generated = doGenerate(src);
cache.put(src, generated);
}
}
}
return generated;
}
private static byte[] doGenerate(byte[] src) {...}
}
有人可以回答,这段代码有什么问题吗? 也许generate()方法可以返回部分构造的数组,不是吗?
答案 0 :(得分:3)
用ConcurrentHashMap替换你的HashMap。
您的同步看起来没用。我会用这种方式重写整个事情:
private static final Map<byte[], byte[]> cache = new ConcurrentHashMap<byte[], byte[]>();
public static byte[] generate(byte[] src, int counter) {
byte[] generated = cache.get(src);
if (generated == null) {
generated = doGenerate(src);
cache.put(src, generated);
}
return generated;
}
编辑:try / catch是奇怪的,没有必要。出于OP的目的,使用ConcurrentHashMap就足够了。如果OP真的不想承担为同一数据集调用doGenerate两次的成本,那么他们将不得不继续使用DCL模式,但仍然建议使用ConcurrentHashMap。
答案 1 :(得分:2)
首先,您使用的是HashMap
非同步。这可能导致无限循环(这是真实的 - 它已在生产环境中观察到)。
它还遇到了一般的双重检查锁定错误,即没有发生在之间的关系,从写入数组的内容到读取它(我假设会有一些数据)
(注意,您在这里比较对象标识,而不是数组内容。)
另一个问题是你有可变的静态,这是一个糟糕的设计,会导致严重的问题。
答案 2 :(得分:0)
当一个线程正在执行第11行时,另一个线程可能正在执行第5行。这就是为什么你需要一个同步的地图,以及为什么当使用非同步的HashMap时你的结果将是不确定的。
此处的解决方案是同步Map(请参阅java.util.Collections#synchronizedMap)。当然,如果使用完全同步的映射,则双重检查锁定(额外优化)将变得多余。