Java 如何避免使用ConcurrentHashMap

Java 如何避免使用ConcurrentHashMap,java,hadoop,Java,Hadoop,我在Hadoop中Reducer类的run()方法中编写了这段代码 @Override public void run(Context context) throws IOException, InterruptedException { setup(context); ConcurrentHashMap<String, HashSet<Text>> map = new ConcurrentHashMap<String, H

我在Hadoop中Reducer类的run()方法中编写了这段代码

@Override
    public void run(Context context) throws IOException, InterruptedException {
        setup(context);

        ConcurrentHashMap<String, HashSet<Text>> map = new ConcurrentHashMap<String, HashSet<Text>>();

        while (context.nextKey()) {
            String line = context.getCurrentKey().toString();
            HashSet<Text> values = new HashSet<Text>();
            for (Text t : context.getValues()) {
                values.add(new Text(t));
            }

            map.put(line, new HashSet<Text>());
            for (Text t : values) {
                map.get(line).add(new Text(t));
            }
        }

        ConcurrentHashMap<String, HashSet<Text>> newMap = new ConcurrentHashMap<String, HashSet<Text>>();

        for (String keyToMerge : map.keySet()) {
            String[] keyToMergeTokens = keyToMerge.split(",");
            for (String key : map.keySet()) {
                String[] keyTokens = key.split(",");
                if (keyToMergeTokens[keyToMergeTokens.length - 1].equals(keyTokens[0])) {
                    String newKey = keyToMerge;
                    for (int i = 1; i < keyTokens.length; i++) {
                        newKey += "," + keyTokens[i];
                    }
                    if (!newMap.contains(newKey)) {
                        newMap.put(newKey, new HashSet<Text>());
                        for (Text t : map.get(keyToMerge)) {
                            newMap.get(newKey).add(new Text(t));
                        }
                    }
                    for (Text t : map.get(key)) {
                        newMap.get(newKey).add(new Text(t));
                    }
                }
            }


        //call the reducers
        for (String key : newMap.keySet()) {
            reduce(new Text(key), newMap.get(key), context);
        }

        cleanup(context);
    }
@覆盖
公共void运行(上下文上下文)引发IOException、InterruptedException{
设置(上下文);
ConcurrentHashMap=新的ConcurrentHashMap();
while(context.nextKey()){
字符串行=context.getCurrentKey().toString();
HashSet值=新的HashSet();
for(文本t:context.getValues()){
添加(新文本(t));
}
put(line,newhashset());
对于(文本t:值){
map.get(line.add)(新文本(t));
}
}
ConcurrentHashMap newMap=新ConcurrentHashMap();
for(字符串keytomege:map.keySet()){
字符串[]keyToMergeTokens=keyToMerge.split(“,”);
for(字符串键:map.keySet()){
String[]keyTokens=key.split(“,”);
if(keyToMergeTokens[keyToMergeTokens.length-1].等于(keyTokens[0])){
字符串newKey=keytomege;
for(int i=1;i
我的问题是,即使我的输入太小,也需要30分钟才能运行,特别是因为newMap.put()调用。如果我将此命令放入注释中,则它运行得很快,没有任何问题。 正如您所看到的,我使用ConcurrentHashMap。我不想使用它,因为我认为run()在每台机器上只调用一次(它不会并发运行),所以使用简单的HashMap不会有任何问题,但如果我用简单的HashMap替换ConcurrentHashMap,我会得到一个错误(concurrentModificationError)。 有没有人知道如何让它毫不拖延地工作? 提前谢谢

*爪哇6
*hadoop 1.2.1

我不知道它是否能解决您的性能问题,但我看到您正在做一件效率低下的事情:

newMap.put(newKey, new HashSet<Text>());
for (Text t : map.get(keyToMerge)) {
    newMap.get(newKey).add(new Text(t));
}
你可以简单地写:

    while (context.nextKey()) {
        String line = context.getCurrentKey().toString();
        HashSet<Text> values = new HashSet<Text>();
        for (Text t : context.getValues()) {
            values.add(new Text(t));
        }

        map.put(line, values);
    }
此代码向您提供
ConcurrentModificationError
的原因是foreach循环不支持修改您正在迭代的集合

要克服此问题,可以使用迭代器:

    //clear map
    Iterator<Map.Entry<String, HashSet<Text>>> iter1 = map.entrySet ().iterator ();
    while (iter1.hasNext()) {
        Map.Entry<String, HashSet<Text>> entry = iter1.next();
        iter1.remove();
    }
    map = null;

    //clear newMap
    Iterator<Map.Entry<String, HashSet<Text>>> iter2 = newMap.entrySet ().iterator ();
    while (iter2.hasNext()) {
        Map.Entry<String, HashSet<Text>> entry = iter2.next();
        iter2.remove();
    }
    newMap = null;

当您删除对映射的引用时,垃圾收集器可以对其进行垃圾收集。从映射中删除项目没有任何区别。

这可能是CodeReview的候选项吗?我不明白。您能解释一下吗?@developer如果您有要改进的工作代码,那么它是一个很好的放置位置。con具体在哪里引发当前修改异常?这几乎可以肯定是由于在遍历键集、入口集或值时对映射进行了变异造成的。使用java6 String.split()方法是性能杀手,请使用org.apache.commons.lang3.StringUtils.splitPreserveAllTokens(String str,char separatorChar)而不是我认为在O(1)中有它的时间到了。无论如何,谢谢你,但这并不是主要问题:(
    while (context.nextKey()) {
        String line = context.getCurrentKey().toString();
        HashSet<Text> values = new HashSet<Text>();
        for (Text t : context.getValues()) {
            values.add(new Text(t));
        }

        map.put(line, values);
    }
    //clear map
    for (String s : map.keySet()) {
        map.remove(s);
    }
    map = null;

    //clear newMap
    for (String s : newMap.keySet()) {
        newMap.remove(s);
    }
    newMap = null;
    //clear map
    Iterator<Map.Entry<String, HashSet<Text>>> iter1 = map.entrySet ().iterator ();
    while (iter1.hasNext()) {
        Map.Entry<String, HashSet<Text>> entry = iter1.next();
        iter1.remove();
    }
    map = null;

    //clear newMap
    Iterator<Map.Entry<String, HashSet<Text>>> iter2 = newMap.entrySet ().iterator ();
    while (iter2.hasNext()) {
        Map.Entry<String, HashSet<Text>> entry = iter2.next();
        iter2.remove();
    }
    newMap = null;
map = null;
newMap = null;