【问题标题】:Java concurrency, stream behaviorJava并发,流行为
【发布时间】:2015-05-07 10:22:12
【问题描述】:

同时调用该类的方法getFirst()getSecond()。它是网络应用程序的一部分。

内部映射也被填充,没有并发。

public class MyClass {
    private Map<String, List<List<String>>> first;

    private Map<String, List<List<String>>> second;

    public MyClass() {
        first = new ConcurrentHashMap<>();
        second = new ConcurrentHashMap<>();
    }

    public Set<String> getFirst(String key, String token, int a, int b) {
        return get(first, key, token, a, b);
    }

    public Set<String> getSecond(String key, String token, int a, int b) {
        return get(second, key, token, a, b);
    }

    private Set<String> get(final Map<String, List<List<String>>> map, final String key, final String token,
        final int a, final int b) {
        Set<String> result = new TreeSet<>();
        map.get(key).stream().filter(i -> i.size() <= b && i.size() >= a).forEach(
            s -> result
                .addAll(s.stream().filter(p -> StringUtils.containsIgnoreCase(p, token)).collect(Collectors.toList())));
        return result;
    }
}

我用ab -n 10000 -c 100(Apache 的实用程序)之类的东西对其进行了测试。我记录下来。我总是得到相同的设置。但是,如果我将 map.get(key).stream() 更改为 map.get(key).parallelStream() 并执行相同的步骤,我有时会得到不同的结果大小(总是更小)。

这是什么?

【问题讨论】:

  • 尝试使用线程安全的集合来收集你的结果。
  • Set 的线程安全版本?
  • @SDmitry:为什么不呢? Collections.newSetFromMap(new ConcurrentSkipListMap&lt;String, Boolean&gt;())
  • @OldCurmudgeon @TagirValeev 通过使用线程安全的 Collection 或 Map,您添加了另一个问题:由于同步锁定导致的争用。在高性能系统中,您希望不惜一切代价避免这种情况。最好在非线程安全的集合上使用线程安全的流操作。一些在Collectors.* 中定义并在stream.collect(...) 中使用的收集器提供了提供线程安全而没有争用的智能方法。

标签: java concurrency java-8 java.util.concurrent


【解决方案1】:

您在并行流的forEach 中使用TreeSet.addAll()forEach 主体可以在不同线程中针对不同元素同时执行多次,TreeSet 不是线程安全的。要快速解决问题,您可以同步修改result 或使用forEachOrdered。但是,flatMap 您的流并在没有forEach 的情况下立即收集它会更清洁、更高效。试试这个版本:

return map.get(key).stream()
        .filter(i -> i.size() <= b && i.size() >= a)
        .flatMap(List::stream).filter(p -> StringUtils.containsIgnoreCase(p, token))
        .collect(Collectors.toCollection(TreeSet::new));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多