2016-04-17 19 views
0

私は問題があります。実行するたびにこのコードが同じ値を返さない場合があります。スレッドセーフではないし、parallel()でいくつかの並行性の問題が発生していると思われます。私はspliteratorを使用しようとしていますが、それは動作しますが、ランタイムは3倍悪いので、sequentalと同じです。どのように私はこれを行うことができますか?parallel()の並行性の問題

Ps: traverseDirectoryは、ディレクトリ内のすべての.txtファイルのBlockingQueueを返します。

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 は私がした単語が発見された行を追跡する必要がある、ということに言及するのを忘れ!

答えて

2

リストはスレッドセーフであることが保証されていないため、ワードリストに書き込むときに、特に追加された値に対応するようにリストが構造的に変更されている場合、リストへの同時書き込みが互いに干渉する可能性があります。ドキュメントでは、その状況のリストへの同期アクセスを保証することを推奨しています。

forEachをこのような並行処理の問題を避けるために、より多くのストリーム処理に置き換える方がよいでしょう。代わりにforEachの、行のすべての単語のすべてのストリームを生成します

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

のようなものを試してみてください。その後、単語の数を得るには.count()でストリームを終了するか、collect()を何らかのコレクションにストリームすることができます。

@Holgerは、正規表現Stringで繰り返し分割すると、すべての繰り返しで同じ正規表現が再コンパイルされることを指摘しました。代わりに

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

正規表現を使用することによってのみ、ファイルごとに一度コンパイルされます。

+1

正しいですが、 '.flatMap(Pattern.compile(" \\ s + "):: splitAsStream)'を使用することをお勧めします。これは、正規表現パターンが各行ではなく1回だけ正確に解析され、各行の中間配列を満たさないことを保証します。 – Holger

+0

@Holger 'splitAsStream'は私にとって新しいものです。あなたのおかげで幸せになれた。 –

+0

@Holger flatMapとはどういう意味ですか? – yeahboy

関連する問題