Java 8 ConcurrentHashMap合并vs computeIfAbsent

时间:2015-01-13 16:18:16

标签: multithreading concurrency merge java-8 concurrenthashmap

我正在练习书#34; Java SE 8 for the Really Impatient"作者:Cay S. Horstmann。有2个练习要求使用同一算法的不同实现,一个使用merge,另一个使用computeIfAbsent。我已使用merge实施了该计划,但无法弄清楚如何使用computeIfAbsent执行相同的操作。在我看来computeIfPresent会更合适,因为merge仅在密钥存在时才有效,computeIfPresent也是如此。

问题陈述:

  

编写一个应用程序,其中多个线程读取a中的所有单词   文件集合。使用ConcurrentHashMap<String, Set<File>>来   跟踪每个单词出现的文件。使用merge方法进行更新   地图。

我的代码使用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);
        }
    }
}

2 个答案:

答案 0 :(得分:2)

专注于必须完成的事情,如果值不存在。您需要做的是为缺席条目创建新的Set值。当然,如果您使用仅对Set创建具有原子性保证的操作,则会同时添加Set,这需要使用并发{ {1}}。您可以通过映射到固定值来利用Set来创建事实上的ConcurrentHashMap(在该格式中不存在),如果您让值信令存在为{{ {1}}:

ConcurrentHashSet

答案 1 :(得分:0)

我使用function get_write_user_values() { var promise = $.ajax({ ... }) // remove the success and error handlers .then(onSuccess, onError) function onSuccess(data) { // do stuff to the data return processed_data; } function onError(err) { console.log('An error with the api'); return err; } return promise; } function get_non_authorized_bulk_edit_option_values() { get_write_user_values() .then (function (processed_data) { alert(processed_data); }); } 并按扩展名“.txt”过滤文件。 结果显示在控制台中。 对于IntelliJ IDEA IDE:如果结果不完整,则检查并增加“覆盖控制台循环缓冲区大小”(文件/设置/编辑器/常规/控制台)。

导入列表:

computeIfAbsent

我解决了这个任务:

import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

致电public static void printMap(Path path){ try (Stream<Path> stream = Files.walk(path)){ ConcurrentHashMap<String, Set<File>> map = new ConcurrentHashMap<>(); stream.parallel() .filter(p -> !(Files.isDirectory(p)) & p.getFileName() .toString() .toLowerCase() .endsWith(".txt")) .collect(Collectors.toList()) .forEach((p) -> { try { Files.lines(p, StandardCharsets.UTF_8) .flatMap(s -> Arrays.asList(s.split("\\PL+")).stream()) .filter(w -> w.length() > 0) .map(String::toLowerCase) .parallel() .forEach( key -> { Set<File> tempSet = new HashSet<>(); tempSet.add(new File(p.toString())); map.computeIfAbsent(key, x -> ConcurrentHashMap.newKeySet()) .addAll(tempSet); }); } catch (IOException e){ } catch (UncheckedIOException e){} }); map.entrySet().stream() .sorted(Map.Entry.comparingByKey()) .forEach(System.out::println); } catch (IOException e){} }

printMap()

如果需要使用public static void main(String[] args){ Path path = Paths.get(*somePathName*); printMap(path); } ,则只需替换

merge

map.computeIfAbsent(key, x -> ConcurrentHashMap.newKeySet()).addAll(tempSet);