[英]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.