合并收藏集的正确方法

时间:2019-06-20 00:21:03

标签: java multithreading list collections java-stream

我已经完成了一些代码以将包含对[String,Integer],示例的并行集合组合在一起

线程1 [Car,1] [Bear,1] [Car,1]

线程2 [River,1] [Car,1] [River,1]

结果应该是每个唯一对密钥的集合(按字母顺序排序)

[熊,1]

[汽车,1] [汽车,1] [汽车,1]

[River,1] [River,1] [River,1]

我执行此操作的解决方案如下所示,但是有时我没有得到预期的结果,或者从包含结果集合的列表中抛出了ConcurrentModificationException

List<Collection<Pair<String, Integer>>> combiningResult = new ArrayList<>();

private void startMappingPhase() throws Exception {
    SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss.SSS");
    Invoker invoker = new Invoker(mappingClsPath, "Mapping", "mapper");
    List<Callable<Integer>> tasks = new ArrayList<>();
    for (String line : fileLines) {
        tasks.add(() -> {
            try {
                combine((Collection<Pair<String, Integer>>) invoker.invoke(line));
            } catch (Exception e) {
                e.printStackTrace();
                executor.shutdownNow();
                errorOccurred = true;
                return 0;
            }
            return 1;
        });

        if (errorOccurred)
            Utils.showFatalError("Some error occurred, See log for more detalis");
    }
    long start = System.nanoTime();
    System.out.println(tasks.size() + " Tasks");
    System.out.println("Started at " + formatter.format(new Date()) + "\n");


    executor.invokeAll(tasks);

    long elapsedTime = System.nanoTime() - start;

    partitioningResult.forEach(c -> {
        System.out.println(c.size() + "\n" + c);
    });


    System.out.print("\nFinished in " + (elapsedTime / 1_000_000_000.0) + " milliseconds\n");
}

private void partition(Collection<Pair<String, Integer>> pairs) {

    Set<Pair<String, Integer>> uniquePairs = new LinkedHashSet<>(pairs);

    for (Pair<String, Integer> uniquePair : uniquePairs) {

        int pFrequencyCount = Collections.frequency(pairs, uniquePair);

        Optional<Collection<Pair<String, Integer>>> collResult = combiningResult.stream().filter(c -> c.contains(uniquePair)).findAny();
        if (collResult.isPresent()) {
            collResult.ifPresent(c -> {
                for (int i = 0; i < pFrequencyCount; i++)
                    c.add(uniquePair);
            });
        } else {
            Collection<Pair<String, Integer>> newColl = new ArrayList<>();
            for (int i = 0; i < pFrequencyCount; i++)
                newColl.add(uniquePair);
            combiningResult.add(newColl);
        }

    }
}

我尝试了坚持ArrayList的CopyOnWriteList,但有时它得到的结果不完整,例如

[Car,1] [Car,1]坚持三个问题,我的问题

有没有一种方法可以实现我要尝试的操作而不会出现ConcurrentModificationException和不完整的结果?

An example image

1 个答案:

答案 0 :(得分:0)

如果您试图从多个线程修改单个集合,则需要添加一个同步块或使用支持并发性的JDK类之一。这些通常比同步块执行得更好。

https://docs.oracle.com/javase/tutorial/essential/concurrency/collections.html