0

텍스트 파일을 구문 분석하고 일부 토큰을 계산하려고합니다. 파일은 한 줄씩 읽히고 모든 줄은 토큰으로 나뉩니다. 토큰을 목록에 넣은 다음 계산하는 방법으로 처리합니다. 토큰은 토큰을 키로하고 금액을 값으로 사용하여 동시 해시 맵에 저장됩니다. 또한 가장 높은 단어 수를 기준으로 이것을 정렬해야합니다.동시 해시 맵을 사용하는이 코드에서 여전히 일종의 경쟁 조건이 있습니까?

하지만 계산 결과가 다르기 때문에 뭔가 놓친 것 같습니다.

private ConcurrentHashMap<String, Integer> wordCount = new ConcurrentHashMap<>(); 
private ExecutorService executorService = Executors.newFixedThreadPool(4); 

private void parseFile(String file) { 

    try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), 
     StandardCharsets.ISO_8859_1))) { 
     String line; 

     ArrayList<String> tokenListForThread; 
     while ((line = reader.readLine()) != null) { 
      tokenListForThread = new ArrayList<>(); 
      StringTokenizer st = new StringTokenizer(line, " .,:!?", false); 
      while (st.hasMoreTokens()) { 
       tokenListForThread.add(st.nextToken()); 
      } 
      startThreads(tokenListForThread); 
     } 
     reader.close(); 
     executorService.shutdown(); 
     executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); 
    } catch (Exception e) { 
     e.printStackTrace(); 
     System.exit(-1); 
    } 
    printWordCount(); 
} 

private void startThreads(ArrayList<String> tokenList) { 
    executorService.execute(() -> countWords(tokenList)); 
} 

private void countWords(ArrayList<String> tokenList) { 
    for (String token : tokenList) { 
     int cnt = wordCount.containsKey(token) ? wordCount.get(token) : 0; 
     wordCount.put(token, cnt + 1); 
     /*if (wordCount.containsKey(token)){ 
      wordCount.put(token, wordCount.get(token)+ 1); 
     } else{ 
      wordCount.putIfAbsent(token, 1); 
     }*/ 
    } 
} 

private void printWordCount() { 
    ArrayList<Integer> results = new ArrayList<>(); 

    for (Map.Entry<String, Integer> entry : wordCount.entrySet()) { 
     results.add(entry.getValue()); 
    } 

    results.sort(Comparator.reverseOrder()); 

    for (int i = 0; i < 10; i++) { 
     Integer tmp = results.get(i); 
     System.out.println(tmp); 
    } 
} 

내 실수는 어디에서 가능합니까? 어떻게 해결할 수 있습니까?

답변

0

토큰 카운트 점진 원자해야하지만, 그 다음, 동시에 같은 cnt를 얻을 수를 증가시키고 다시 넣을 수 있습니다 토큰 목록에서 같은 토큰 '과

int cnt = wordCount.containsKey(token) ? wordCount.get(token) : 0; 
wordCount.put(token, cnt + 1); 

두 개의 스레드가 아니다. 즉 전체 카운트가 실제 카운트보다 낮을 수 있습니다.

는 아직 token이없는 경우 AtomicIntegerwordCount 같은 값

wordCount.putIfAbsent(token, new AtomicInteger()); 
wordCount.get(token).incrementAndGet(); 

1 단계을 사용할 수 있습니다 초기 접근 방식을 변경하지 않고 그것을 해결하기 위해,하지만 당신은 추가 할 것입니다. 토큰 및 zero 수가지도에 입력되어야합니다. putIfAbsent 메서드는 원자 적이며 동시적인 문제를 방지 할 수 있습니다.

2 단계 주어진 토큰에 해당하는 AtomicInteger에 대한 참조를 가져 와서 증가시킵니다. 이 작업은 스레드 저장 중 하나입니다.

+0

감사합니다. -이 사실을 알지 못했습니다. – Faulek