CUBは子供の白熊

Java SE 8 実践プログラミングの練習問題を解く

第6章 並行処理の機能強化 : 問題 6 : ConcurrentHashMap の computeIfAbsent メソッド

問題

複数スレッドが複数のファイルから全ての単語を読み込むアプリケーションを書け

各々の単語がどのファイルで使用されていたかを管理するためにConcurrentHashMap<String,Set<File>>computeIfAbsentメソッドを使用せよ

準備

読み込むテキストファイルは問題 5 と同じ5つで、総バイト数は 7.7メガ

単語の読み込みは、問題 5 で定義したWordReaderクラスを使う

解答

じゃConcurrentHashMapcomputeIfAbsentを使ってみよう
mergeと違って Value であるSet<File>の競合を考慮しなくてはいけない

ConcurrentHashMap<String, Set<File>> map = new ConcurrentHashMap<>();
CountDownLatch latch = new CountDownLatch(5/* ちょっとダサいけど… */);
ExecutorService pool = Executors.newCachedThreadPool();
for (File file : new File(".").listFiles(f -> f.getName().endsWith(".txt"))) {
    pool.submit(
        () -> {
            try {
                try (WordReader reader = new WordReader(file)) {
                    String word;
                    while ((word = reader.getWord()) != null) {
                        map.computeIfAbsent(
                            word,
                            key -> ConcurrentHashMap.newKeySet()
                        ).add(file);
                    }
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            latch.countDown();
        }
    );
}
pool.shutdown();
latch.await();

さらに問題

この方法の利点は何か?

解答

毎回Set<File>を生成しないで必要なときだけ新しいSet<File>を生成するので、メモリ効率が良い

実際、mergeメソッドより高速である