多线程 – Java 8 ConcurrentHashMap merge与computeIfAbsent

我正在使用Cay S. Horstmann的书“
Java SE 8 for the Really Impatient”进行练习.有两个练习要求同一算法的不同实现,一个使用合并,另一个使用computeIfAbsent.我已经使用merge实现了该程序,但无法弄清楚如何使用computeIfAbsent来做同样的事情.在我看来,computeIfPresent更适合,因为merge仅在密钥存在时才有效,而computeIfPresent也是如此.

问题陈述:

Write an application in which multiple threads read all words from a
collection of files. Use a ConcurrentHashMap<String, Set<File>> to
track in which files each word occurs. Use the merge method to update
the map.

我的代码使用merge:

public static Map<String, Set<File>> reverseIndexUsingMerge(final Path path)
        throws IOException {
    final ConcurrentHashMap<String, Set<File>> map = new ConcurrentHashMap<>();

    final BiConsumer<? super String, ? super Set<File>> action = (key,
        value) -> map.merge(key, value, (existingValue, newValue) -> {
        LOGGER.info("Received key: {}, existing value: {}, new value: {}.",
            key, existingValue, newValue);

        newValue.addAll(existingValue);

        return newValue;
    });

    commonPool().invokeAll(
        find(path, 1,
            (p, fileAttributes) -> fileAttributes.isRegularFile())
            .map(p -> new ReverseIndex(p, action))
            .collect(toList()));

    return unmodifiableMap(map);
}

private static class ReverseIndex implements Callable<Void> {
    private final Path p;
    private final BiConsumer<? super String, ? super Set<File>> action;

    private static final Pattern AROUND_WHITESPACE = compile("\\s");

    private ReverseIndex(final Path p,
        final BiConsumer<? super String, ? super Set<File>> action) {
        this.p = p;
        this.action = action;
    }

    @Override
    public Void call() throws Exception {
        reverseIndex().forEach(action);

        return null;
    }

    private Map<String, Set<File>> reverseIndex() {
        /* File stream needs to be closed. */
        try (Stream<String> lines = lines(p, UTF_8)) {
        return lines.flatMap(AROUND_WHITESPACE::splitAsStream)
            .collect(
                groupingBy(String::toString,
                    mapping(word -> p.toFile(), toSet())));
        } catch (IOException e) {
        LOGGER.error("Something went wrong. Get the hell outta here.",
            e);

        throw new UncheckedIOException(e);
        }
    }
}

最佳答案 如果价值不存在,请关注必须做的事情.您需要做的是为缺席条目创建新的Set值.当然,如果您使用具有原子性保证的操作来创建Set,则添加到Set将同时发生,这需要使用并发Set.您可以利用ConcurrentHashMap通过映射到固定值来创建事实上的ConcurrentHashSet(在该表单中不存在),如果您让值信令存在为Boolean,则这一点特别简单.TRUE:

ConcurrentHashMap<String, Set<File>> map=new ConcurrentHashMap<>();
final BiConsumer<? super String, ? super Set<File>> action =
    (key, value) -> map.computeIfAbsent(key, x->ConcurrentHashMap.newKeySet())
                       .addAll(value);
点赞