"Cay S Horstman"による "Java SE 8 for Really Impatient"の演習5第6章を解決しようとしています。ここに質問があります:ConcurrentHashMapで「マージ」メソッドを正しく使用する方法は?
複数のスレッドがファイルのコレクションからすべての単語を読み取るアプリケーションを作成します。 ConcurrentHashMap>を使用して、各単語が含まれるファイルを追跡します。マージメソッドを使用してマップを更新します。
私はこのようにこの演習を解決しようとした: 私は4つのファイルFILE1.TXT、FILE2.TXT、file3.txtを作成し、
FILE1.TXTがこれらのコンテンツを持っているfile4.txt:
Word1
FILE2.TXTは、これらのコンテンツを持っている:
Word1 Word2
file3.txtは、これらのコンテンツを持っている:
Word1 Word2 Word3
file4.txtは、これらのコンテンツを持っている:
Word1 Word2 Word3 Word4
は、私はクラス指定されたディレクトリ内の4以上のファイルのリストを取得する「Problem5.java」を実施しました。このクラスには、 "merge"メソッドを使用して更新される静的ConcurrentHashMap "stringToFileMap"があります。このクラスは、ファイルごとにStringToFileMapperオブジェクトを作成し、executorサービスを使用してすべての呼び出し可能ファイルを呼び出します。フューチャーがエグゼキュータ・サービスから戻されると、同時ハッシュ・マップの内容が出力されます。
Problem5.java
package problem5;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.*;
public class Problem5 {
public static final ConcurrentHashMap<String, Set<File>> stringToFileMap = new ConcurrentHashMap<>();
private File[] files;
private ExecutorService executorService;
public Problem5(String dirName){
executorService = Executors.newFixedThreadPool(2);
File dir = new File(dirName);
files = dir.listFiles((dir1, name) -> name.endsWith(".txt"));
}
public void execute() throws InterruptedException, ExecutionException {
List<Future<Long>> futureList;
Collection<StringToFileMapper> callables = new ArrayList<>();
for(File file: files){
callables.add(new StringToFileMapper(file));
}
futureList = executorService.invokeAll(callables);
stringToFileMap.forEach((String key, Set<File> files) -> {
StringBuilder fileNames = new StringBuilder();
for(File file: files){
fileNames.append(file.getName());
fileNames.append(", ");
}
System.out.println(key+" is present in files "+fileNames.toString());
});
System.out.println("Hashmap size = "+ stringToFileMap.size());
executorService.shutdown();
stringToFileMap.clear();
}
}
私は、ファイルやアップデートConcurrentHashMapの "stringToFileMap" から単語を読み込み、呼び出し可能なクラス "StringToFileMapper.java" を実施しました。
StringToFileMapper.java:
package problem5;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.math.BigInteger;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.stream.Stream;
public final class StringToFileMapper implements Callable<Long> {
private final File file;
public StringToFileMapper(File file){
this.file = file;
}
@Override
public Long call() throws Exception {
Long count = 0l;
try (BufferedReader reader = new BufferedReader(new FileReader(this.file))){
Set<File> fileSet = ConcurrentHashMap.newKeySet();
fileSet.add(this.file);
Stream<String> lineStream = reader.lines();
lineStream.forEach(line -> {
String[] words = line.split(" ");
for(String word: words){
//count = count.add(BigInteger.ONE);
BiFunction<Set<File>, Set<File>, Set<File>> reMappingFunction = (Set<File> oldSet, Set<File> newSet) -> {
oldSet.addAll(newSet);
return oldSet;
};
System.out.println("Word " +word+" is in "+ this.file.getName());
Problem5.stringToFileMap.merge(word, fileSet, reMappingFunction);
}
});
}
return count;
}
}
あなたは上記を参照できるように、私はConcurrentHashMapの中で機能を "マージ" と一緒にBiFunction "reMappingFunction" を使用。
Problem5.javaはテキストファイルのディレクトリパスでインスタンス化し、その "execute"メソッドを呼び出すmain関数から呼び出されます。
import problem1.Problem1;
import problem3.Problem3;
import problem5.Problem5;
import java.util.concurrent.ExecutionException;
public class Main {
public static void main(String[] args) throws InterruptedException, ExecutionException {
Problem5 problem5 = new Problem5("src/problem1");
problem5.execute();
}
}
上記のプログラムを実行すると、正しい出力が印刷されることがあります。間違った出力が印刷されることがあります。
正しい出力
objc[36588]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/bin/java (0x1064e64c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x1065ae4e0). One of the two will be used. Which one is undefined.
Word Word1 is in file1.txt
Word Word1 is in file2.txt
Word Word2 is in file2.txt
Word Word1 is in file3.txt
Word Word2 is in file3.txt
Word Word3 is in file3.txt
Word Word1 is in file4.txt
Word Word2 is in file4.txt
Word Word3 is in file4.txt
Word Word4 is in file4.txt
Word4 is present in files file4.txt,
Word2 is present in files file4.txt, file2.txt, file3.txt,
Word3 is present in files file4.txt, file3.txt,
Word1 is present in files file4.txt, file1.txt, file2.txt, file3.txt,
Hashmap size = 4
Process finished with exit code 0
間違った出力
objc[36672]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/bin/java (0x10c8f04c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x10c9b84e0). One of the two will be used. Which one is undefined.
Word Word1 is in file2.txt
Word Word1 is in file1.txt
Word Word2 is in file2.txt
Word Word1 is in file3.txt
Word Word2 is in file3.txt
Word Word3 is in file3.txt
Word Word1 is in file4.txt
Word Word2 is in file4.txt
Word Word3 is in file4.txt
Word Word4 is in file4.txt
Word4 is present in files file4.txt,
Word2 is present in files file4.txt, file2.txt, file1.txt, file3.txt,
Word3 is present in files file4.txt, file3.txt,
Word1 is present in files file4.txt, file2.txt, file1.txt, file3.txt,
Hashmap size = 4
Process finished with exit code 0
間違った出力の上で見ることができるように、問題の5.javaで同時ハッシュマップからの出力はどこ出力として、間違っていますStringToFileMapper.javaのsysoutから正しいものがあります。
私は上記のプログラムが時々動作しない理由を理解できません。
「複数のスレッドがあるアプリケーションを作成する」複数のスレッドを使用する場所はまったくありません。あなたはrunnableを実装していないか、スレッドクラスを拡張していません –
私の悪いです。私はこれがJava 8の新機能であることに気付きました。私の学校はJava 7を教えています。 –
@JeremiahStillings executorService = Executors.newFixedThreadPool(2);を使用して複数のスレッドを作成しています。 executorService.invokeAll(callables)を使用して複数のスレッドを呼び出す。 – krishna2642