以下代码是否设置为正确同步呼叫synchronizedMap
?
public class MyClass {
private static Map<String, List<String>> synchronizedMap = Collections.synchronizedMap(new HashMap<String, List<String>>());
public void doWork(String key) {
List<String> values = null;
while ((values = synchronizedMap.remove(key)) != null) {
//do something with values
}
}
public static void addToMap(String key, String value) {
synchronized (synchronizedMap) {
if (synchronizedMap.containsKey(key)) {
synchronizedMap.get(key).add(value);
}
else {
List<String> valuesList = new ArrayList<String>();
valuesList.add(value);
synchronizedMap.put(key, valuesList);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
根据我的理解,我需要同步块addToMap()
来防止另一个线程调用remove()
或containsKey()
在我通过调用之前put()
但我不需要同步块doWork()
因为另一个线程无法addToMap() …
在任何人对使用的事实提出质疑之前string.intern()
,请允许我说在我的特定应用程序中出于内存和性能原因需要它.[1]
所以,直到现在我使用String.intern()
并假设它是最有效的方法.但是,我注意到它已经成为软件的瓶颈.[2]
然后,就在最近,我试图String.intern()
用一个巨大的地图替换我放置/获取字符串,以便每次获得一个唯一的实例.我预计这会慢一点......但恰恰相反!它速度非常快!intern()
通过推动/轮询地图(实现完全相同)来替换,导致速度提高了一个数量级以上.
问题是:为什么intern()
这么慢?!?那么为什么它不是简单地由地图(实际上只是一个定制的集合)备份而且速度会快得多?我很困惑.
[1]:对于不相信的人:它是在自然语言处理中并且必须处理千兆字节的文本,因此需要避免相同字符串的许多实例以避免炸毁内存和引用字符串比较足够快.
[2]:没有它(正常的字符串)是不可能的,有了它,这个特定的步骤仍然是计算密集程度最高的一步
编辑:
由于对这篇文章的惊人兴趣,这里有一些代码来测试它:
而实习结果超过100万字符串:
HashMap
:4秒String.intern()
:54秒由于避免了一些预热/ OS IO缓存和类似的东西,通过颠倒两个基准的顺序重复实验:
String.intern()
:69秒HashMap
:3秒如你所见,差异非常显着,超过十倍.(使用OpenJDK 1.6.0_22 64位...但使用太阳一个导致类似的结果我认为)