繁体   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