第6章 並行処理の機能強化 : 問題 6 : ConcurrentHashMap の computeIfAbsent メソッド
問題
複数スレッドが複数のファイルから全ての単語を読み込むアプリケーションを書け
各々の単語がどのファイルで使用されていたかを管理するためにConcurrentHashMap<String,Set<File>>
とcomputeIfAbsent
メソッドを使用せよ
準備
読み込むテキストファイルは問題 5 と同じ5つで、総バイト数は 7.7メガ
単語の読み込みは、問題 5 で定義したWordReader
クラスを使う
解答
じゃConcurrentHashMap
のcomputeIfAbsent
を使ってみよう
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
メソッドより高速である