2017-10-13 2 views
0

"Cay S Horstman"이 5 권 6 권, "Java SE 8 for Really Impatient"를 해결하려고합니다. 다음은 질문입니다.ConcurrentHashMap에서 "병합"메서드를 올바르게 사용하는 방법?

여러 스레드가 파일 모음에서 모든 단어를 읽는 응용 프로그램을 작성하십시오. 각 단어가 나오는 파일을 추적하려면 ConcurrentHashMap>을 사용하십시오. 병합 메서드를 사용하여지도를 업데이트하십시오.

Word1 
:

은 File2.txt이 내용을 가지고 file4.txt, 내가 4 개 파일은 File2.txt, file2.txt, file3.txt을 만들어 :

는이 같은이 연습을 해결하기 위해 시도

Word1 Word2 

file3.txt이있다 이러한 내용 :

0

file2.txt는 이러한 내용을 가지고

file4.txt는 이러한 내용이 있습니다

Word1 Word2 Word3 Word4 

내가 클래스 지정된 디렉토리에서 4 위의 파일의 목록을 가져옵니다 "Problem5.java"를 구현했습니다. 이 클래스에는 "merge"메소드를 사용하여 업데이트되는 정적 ConcurrentHashMap "stringToFileMap"이 있습니다. 이 클래스는 각 파일에 대해 StringToFileMapper 객체를 만든 다음 Executor 서비스를 사용하여 모든 호출 가능 객체를 호출합니다. 미래가 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에서 올바른지 확인하십시오.

위의 프로그램이 때때로 작동하지 않는 이유를 알 수 없습니다.

+0

"여러 스레드가있는 응용 프로그램 작성"여러 스레드를 사용하는 위치가 전혀 표시되지 않습니다. 당신은 runnable을 구현하지 않고 스레드 클래스를 확장하지 않습니다. –

+0

제 잘못입니다. 방금 Java 8의 새로운 기능인 것을 깨달았습니다. 학교는 Java 7을 가르치고 있습니다. –

+0

@JeremiahStillings executorService = Executors.newFixedThreadPool (2); executorService.invokeAll (callables)를 사용하여 여러 스레드를 호출합니다. – krishna2642

답변

0

이 문제의 해결책을 찾았습니다. 병합 메서드의 BiFunction 인수는 기존 집합을 수정하는 대신 새 집합을 반환해야합니다. 올바른 "BiFunction"인수는 다음과 같습니다.

BiFunction<Set<File>, Set<File>, Set<File>> reMappingFunction = (Set<File> oldSet, Set<File> newSet) -> { 
        Set<File> temp = new HashSet<>(); 
        temp.addAll(newSet); 
        temp.addAll(oldSet); 
        return temp; 
       }; 
관련 문제