Java并发,流行为

Java并发,流行为,java,concurrency,java-8,java.util.concurrent,Java,Concurrency,Java 8,Java.util.concurrent,同时调用此类的方法getFirst()和getSecond()。它是web应用程序的一部分 内部映射也已填充,没有并发性 public class MyClass { private Map<String, List<List<String>>> first; private Map<String, List<List<String>>> second; public MyClass() {

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

内部映射也已填充,没有并发性

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;
    }
}
公共类MyClass{
私人地图优先;
私人地图第二;
公共MyClass(){
first=新的ConcurrentHashMap();
第二个=新的ConcurrentHashMap();
}
公共集getFirst(字符串键、字符串标记、int a、int b){
返回get(第一个,键,令牌,a,b);
}
公共设置getSecond(字符串键、字符串标记、int a、int b){
返回get(秒、键、令牌、a、b);
}
私有集get(最终映射、最终字符串键、最终字符串令牌、,
最终积分a,最终积分b){
设置结果=新树集();
map.get(key.stream().filter(i->i.size()=a).forEach(
s->结果
.addAll(s.stream().filter(p->StringUtils.containsIgnoreCase(p,token)).collect(collector.toList());
返回结果;
}
}
我用类似于
ab-n1000-c100
(Apache的实用程序)的东西测试了它。我把它记录下来。我总是得到同一套。但是,如果我将
map.get(key).stream()
更改为
map.get(key).parallelStream()
并执行相同的步骤,有时会得到不同的结果大小(总是更小)


它是什么?

您正在并行流的
forEach
中使用
TreeSet.addAll()
。forEach主体可以在不同的线程中针对不同的元素同时执行多次,并且不是线程安全的。要快速解决此问题,您可以同步修改
结果
或使用。但是,它会更干净,对您的流更有效,并且可以在不使用
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));
返回map.get(key.stream())
.filter(i->i.size()=a)
.flatMap(List::stream).filter(p->StringUtils.containsSignoreCase(p,令牌))
.collect(收集器.toCollection(TreeSet::new));

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