[英]Java Performance using Concurrency
码:
public class SlowDictionary {
private final Map<String,String> dict = new HashMap<String,String>();
public synchronized String translate (String word)
throws IllegalArgumentException {
if (!dict.containsKey(word)) {
throw new IllegalArgumentException(word + " not found.");
}
return dict.get(word);
}
public synchronized void addToDictionary (String word, String translation)
throws IllegalArgumentException {
if (dict.containsKey(word)) {
throw new IllegalArgumentException(word + " already exists.");
}
dict.put(word,translation);
}
public synchronized Set<String> getAllWords () {
return dict.keySet();
}
}
你要做的第一件事是摆脱所有同步的关键词。
最简单的方法是将dict声明为ConcurrentHashMap:
private final ConcurrentMap<String,String> dict = new ConcurrentHashMap<String,String>();
这样做你可以移除翻译的同步部分,所以它看起来像:
public String translate (String word) throws IllegalArgumentException { ..
其原因是CCHM关于最新读数的合同。
最后,添加到字典可以看起来像:
public void addToDictionary (String word, String translation) throws IllegalArgumentException {
if (dict.putIfAbsent(word,translation)!=null) {
throw new IllegalArgumentException(word + " already exists.");
}
}
同时从getAllWords中删除synchronized。
编辑:在思考汤姆的评论之后。 在这个“例外情况”中进行双重查看可能不值得。 如果案件没有抛出异常那么这是合适的。
转储所有已synchronized
关键字并将dict
定义为ConcurrentHashMap
可能值得尝试。
ConcurrentHashMap
而不是synchronized
。 注意, getAllWords
方法不是线程安全的,或者至少,它返回的Set
不是。
当您说提高性能时,您对使用统计信息有任何了解吗? 例如,对读取的写入次数以及内部映射的大小是多少?
如果读取的数量成比例地高并且地图主要在启动时填充(并且不是很大),则写入时复制策略可能是您最好的选择。 我们使用(并维护)一个CopyOnWriteMap ,它比ConcurrentHashMap具有更好的并发读取性能(在我们的测试中大约10%)。
您应该使用ConcurrentHashMap,但是对于当前的实现,getAllWords()仅在synchronized块内的数据上具有线程安全副本,即除非调用者同步匹配,否则它不是线程安全的。 解决此问题的一种方法是在返回之前获取副本(或使用ConcurrentHashMap)
在以下示例中,每个方法访问一次映射,而不是两次。 (没有同步)
public class SlowDictionary {
private final ConcurrentMap<String,String> dict = new ConcurentHashMap<String,String>();
public String translate (String word) throws IllegalArgumentException {
String translation = dict.get(word);
if (translation == null)
throw new IllegalArgumentException(word + " not found.");
return translation;
}
public void addToDictionary (String word, String translation) throws IllegalArgumentException {
if (dict.putIfAbsent(word, translation) != null)
throw new IllegalArgumentException(word + " already exists.");
}
public Set<String> getAllWords () {
return dict.keySet();
}
}
我可以离开这里,但看起来和你一样好。 那里基本上是cookie切割器同步映射访问器。
如果你有更多的读取而不是写入(通常就是这种情况),考虑使用ReadWriteLock这样读者就不会互相阻塞。
有很多有效的方法来存储词典。 使用像Java的默认HashMap和String对象这样的重量级东西不是其中之一。
所以,当然,你可以摆脱synchronized关键字,尝试通过解决Java idiosynchrasies左右来获得一点点速度。
当然,Map的包含是O(1)......但是当你在其中放入数百万个字符串时,调整大小的地图不是O(1);)
深思熟虑:确定一个单词是否存在使用,例如,Trie,可能比简单地计算一个String的哈希码更快(我不是说你需要的是一个trie:我所说的只是:还有更多比起“让我们使用HashMap,它是O(1),所以你无法击败那个” - 眼睛一样。
而且我可以告诉你,比如谷歌的'翻译'和谷歌的'找你是你的类型'肯定没有通过在I-need-constant-resizing-and-I-resize-存储数百万个Java String对象来实现-非常慢的 Java HashMaps。
你有什么要求? 多少字? 支持多少种语言?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.