簡體   English   中英

使用並發的Java性能

[英]Java Performance using Concurrency

  1. 如何提高這一塊代碼的性能?
  2. 給定問題陳述的單元測試案例是什么?

碼:

    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可能值得嘗試。

  1. 構造和拋出異常很慢,所以不要這樣做。
  2. 確保在每種方法中僅使用單個地圖操作,而不是將查找加倍。
  3. 如果並發使用,請使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM