2011-01-26 4 views
5

ブライアン・ゲッツ氏は、フォーク・ジョイントに関する素敵な記事をhttp://www.ibm.com/developerworks/java/library/j-jtp03048.htmlに書いています。その中で、彼は並行して配列の2つの側で並べ替えを実行し、結果をマージするfork-joinメカニズムを使用してマージソートアルゴリズムをリストします。フォーク・ジョインでのメモリの可視性

アルゴリズムは、同じアレイの2つの異なるセクションを同時にソートします。可視性を維持するためにAtomicIntegerArrayやその他のメカニズムが必要でないのはなぜですか?あるスレッドが他のスレッドが行った書き込みを見るか、これは微妙なバグですか?フォローアップとして、ScalaのForkJoinSchedulerもこの保証をしていますか?

ありがとうございます!

+0

アレイのさまざまなセクションで動作しています。マージするまでは競合はありません。 –

+3

私は彼らが異なるセクションで動作していることに同意します。しかし、Javaのメモリモデルのセマンティクスは、すべてのスレッドがすべての書き込みを見ることが保証されているわけではない(変数がvolatileでない限り)。このブログによると:http://jeremymanson.blogspot.com/2009/06/volatile-arrays-in-java.html揮発性int []を使用するだけでは、他のスレッドが配列への書き込みを見ることを保証するには不十分です –

答えて

5

(ForkJoinの)結合には、最も重要な情報である同期ポイントが必要です。同期点は、発生したすべての書き込みが前記点の後に見えることを保証する。

コードを見ると、同期点の発生場所がわかります。これは、別のプロセスに一つだけここで

public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2) { 
    t2.fork(); 
    t1.invoke(); 
    t2.join(); 
} 

invokeAllメソッド呼び出しt2のフォークで、t1)は(そのタスクを実行し、呼び出し元のスレッドがt2.joinに待機します。 t2を通過するとき。 t1とt2へのすべての書き込みが表示されます。

編集:この編集は、私が同期点の意味を少し説明したものです。

は、次の2つの変数

int x; 
volatile int y; 

あなたがyにあなたはyが利用できるようになります読む前に起こったすべての書き込みを書く任意の時間を持っていると言うことができます。例えば

public void doWork(){ 
    x = 10; 
    y = 5; 
} 

ために別のスレッドは、Yは、スレッドは、Yへの書き込みがすべての書き込みが前のポイントがされることを特徴とする同期ポイントを作成するため、これはX = 10を読み出すためにを保証されること5 =読み取る場合書き込み後に表示されます。

Fork Joinプールでは、ForkJoinTaskの結合によって同期ポイントが作成されます。今度は、t2.fork()とt1.invoke()がt2に参加すると、以前に発生したすべての書き込みが確実に表示されます。以前の書き込みはすべて同じ構造内にあるので、可視性は安全です。

それが明らかでない場合は、さらに説明していただきたいと思います。

+0

'coInvoke'によって' invokeAll'が呼び出されていますか? –

+0

答えを補足するだけで、http://java.sun.com/docs/books/jls/third_edition/html/memory.html#64058も参照してください。 –

+0

@Danciel C. Sobral興味深いことに、私がこの例を書いていたとき、私は実際にcoInvokeメソッドを探していました。 coInvokeメソッド自体がソースコードから削除されたようです。少なくとも私はもうそれを見つけることができません。 –

1

マージにはスレッド上での結合が含まれており、結合によって可視性が保証されます。

2番目の部分は確信しています。私はどのようにマージが実装されているのか分かりません。