自定义谓词有时会返回随机结果

问题描述 投票:0回答:1

我的要求是找出具有给定条件的所有匹配对象。因此,我做了一个创建自定义谓词的操作,并通过了匹配条件和应该与对象匹配的源ID。如果条件匹配,那么我在内部填充地图以保存详细信息。

并且当流完成时,此映射将具有所有匹配条件的详细信息。因此,我将此地图用于以后的计算。在大多数情况下,它可以工作,但会随机开始失败。

我的自定义谓词是-

public class IdentifierMapPredicate<T extends Identifiable, V> implements Predicate<T> {
    private static Logger           logger               = Logger
            .getLogger();
    private Collection<V>                  sourceIds;
    private BiPredicate<T, V>              matchingCondition;
    private Map<V, Collection<Identifier>> identifierMap;

    public Map<V, Collection<Identifier>> getIdentifierMap() {
        return identifierMap;
    }

    public IdentifierMapPredicate(Collection<V> sourceIds,
            BiPredicate<T, V> matchingCondition) {
        this.sourceIds = sourceIds;
        this.matchingCondition = matchingCondition;
        identifierMap = new HashMap<>(sourceIds.size());
    }

    @Override
    public boolean test(T t) {
        for (V id : sourceIds) {
            if (matchingCondition.test(t, id)) {
                //logger.debug("t :{}, id :{}", t.getIdentifier(), id);
                Collection<Identifier> ids = identifierMap.get(id);
                if(ids == null){
                    ids = new HashSet<>();
                    identifierMap.put(id, ids);
                }
                ids.add(t.getIdentifier());
                logger.debug("identifierMap :{}", identifierMap);
                return true;
            }
        }
        return false;
    }
}

我在符合条件时添加了日志语句,并且我们更新了地图,有时地图只有1个元素(即使我期望是2个元素),有时也只有0个元素。

2019-11-24 09:31:52.574 PST调试ForkJoinPool.commonPool-worker-5 IdentifierMapPredicate:52-identifierMap:{}

2019-11-24 09:31:52.574 PST调试ForkJoinPool.commonPool-worker-7 IdentifierMapPredicate:52 -identifierMap:{}

以上实现有什么问题吗?将其更改为ConcurrentHashMap应该会有所帮助吗?

java lambda java-8 predicate
1个回答
1
投票

在大多数情况下,它可以正常工作,但会随机失败

是的,经典race condition

您正在多线程上下文中使用IdentifierMapPredicate。如果您同时访问IdentifierMapPredicate.test,线程将同时使用identifierMap,这不是线程安全的。

如果您还为HashSet使用线程保存替代方案,就像@Ivan指出的那样,看起来ConcurrentHashMap将解决此问题。另外,您可以使用test关键字修改方法synchronized,但这将给您带来更少的吞吐量/更多的锁定。但是另一方面,也减少了头痛,这是一个折衷,如果没有严格的性能要求,我很乐意接受较少的头痛。

顺便说一句。现在,您可以使用Map。computeIfAbsent创建新的ids

© www.soinside.com 2019 - 2024. All rights reserved.