2016-04-17 14 views
0

Ich habe ein Problem, wo dieser Code nicht den gleichen Wert jedes Mal zurückgibt, wenn es ausgeführt wird. Ich nehme an, es liegt daran, dass es nicht threadsicher ist und ich Parallelitätsprobleme mit Parallelität() habe. Ich habe versucht, einen Spliterator zu verwenden, und das funktioniert, aber Laufzeit, weil 3 Mal schlechter, das gleiche wie sequential. Wie sonst kann ich das tun?Parallelitätsprobleme mit parallel()

Ps: traverseDirectory gibt eine BlockingQueue aller TXT-Dateien in einem Verzeichnis zurück.

try { 
    pq = traverseDirectory(dir, pq); 

    while(!pq.isEmpty()){ 

     File f = pq.take(); 
     LineNumberReader lr = new LineNumberReader(new FileReader(f)); 
     lr.lines() 
      .parallel() 
      .forEach((line) -> { 
       String[] words = line.split("\\s+"); 
       for(String word : words){ 
        wordList.add(word); 
       } 

      }); // foreach 

    } // while 

} //try 
catch (IOException | InterruptedException e) {} 

System.out.println("size: " + wordList.size()); 

EDIT ich vergaß zu erwähnen, dass ich den Überblick behalten müssen in welcher Zeile das Wort gefunden wurde!

Antwort

2

Es ist nicht garantiert, dass Listen threadsicher sind. Wenn Sie also in Ihre Wortliste schreiben, können sich gleichzeitige Schreibvorgänge gegenseitig stören, insbesondere wenn die Liste strukturell geändert wird, um zusätzliche Werte zu berücksichtigen. Die Dokumentation empfiehlt, in dieser Situation den synchronisierten Zugriff auf die Liste zu gewährleisten.

Sie sind besser dran, die forEach durch mehr Stream-Verarbeitung zu ersetzen, um solche Nebenläufigkeitsprobleme zu vermeiden. Anstelle des forEach, versuchen Sie so etwas wie

.flatMap(line -> Arrays.stream(line.split("\\s+"))) 

dass ein Strom von allen Wörtern in allen Zeilen ergibt. Sie könnten dann den Stream mit .count() beenden, um die Anzahl der Wörter zu erhalten, oder collect() sie zu einer Sammlung einer Art.

@Holger wies darauf hin, dass durch wiederholtes Teilen mit einer String Regex die gleiche Regex bei jeder Iteration neu kompiliert wird. Bei Verwendung von

.flatMap(Pattern.compile("\\s+")::splitAsStream) 

wird die Regex nur einmal pro Datei kompiliert.

+1

Korrekt, aber Sie können stattdessen '.flatMap (Pattern.compile (" \\ s + ") :: splitAsStream)' stattdessen verwenden. Es stellt sicher, dass das Regex-Muster genau einmal statt für jede Zeile geparst wird, und es wird kein Zwischenfeld für jede Zeile gefüllt. – Holger

+0

@Holger 'splitAsStream' ist ein neues für mich. Du hast meinen Tag gerettet. –

+0

@Holger Was genau macht flatMap? – yeahboy