ここでは、の改良である:[STACK-REF] In Java, is it required to synchronize write access to an array if each thread writes to a separate cell space?Java:配列の内容は、他のスレッドによって更新された後、自動的に更新されます。同期ステートメントはありません。
コンテキスト:我々は、統計的計算を行うために、行型の巨大なアレイに必要。 [STACK-REF]配列コンテンツをN(ワーカー)スレッドで同時に処理できることを発見しましょう。
問題:メインスレッドT0がN個のワーカーを起動します。すべての労働者が終わったら、T0は何をアレイで見ていますか?その主体はメインメモリと同期していますか?
(単純な)テストケース:8件の商品:
- スレッドT0バイトの小さな配列を作成します。
- 8つの別個の値を書き込む新しい新しいスレッドT1を開始します。
- T0は、ウェイクアップ前にT1が終了するように、長時間待ってください。 T1は、それを構築したようT0はそれを見て:
- アレイ含量は(T0によって)
検索結果を表示します。 これはかなり正常なのか偶発的なのでしょうか?
public class TestCase extends Thread {
public static void main(String[] args) throws InterruptedException {
//Current thread (main) stands for 'T0' in topic description.
// byte : to get a very small array.
byte[] counts = { (byte) 128, (byte) 129, (byte) 130,
(byte) 131, (byte) 132, (byte) 133,
(byte) 134, (byte) 135 };
StringBuilder sb = new StringBuilder();
for (int i = 0; i < counts.length; i++)
sb.append(counts[i]+" ");
// all values are displays as negative numbers
System.out.println("'counts' initial content = " + sb);
Thread T1 = new TestCase(counts);
T1.start();
// 'join' can't be suspected to do refresh 'counts' array.
// T1.join();
Thread.sleep(1000);
//Avoid to display each item, to avoid any unexpected
// sync, as explained in :
// see : https://stackoverflow.com/questions/21583448/what-can-force-a-non-volatile-variable-to-be-refreshed
// for (int i = 0; i < counts.length; i++)
// System.out.println(counts[i]+" ");
sb = new StringBuilder();
for (int i = 0; i < counts.length; i++)
sb.append(counts[i]+" ");
// all values are displayed as written by thread T1
//How 'counts' copy in L1 cache has been updated from main memory ?
System.out.println("'counts' post content = " + sb);
}
配列のサイズが小さいと、我々は、各スレッドがそのL1/2/...キャッシュ(> = 32KO)での完全なコピーを所有していることを想像してみてください。 T1が終了すると、アレイはメインメモリで完全に更新されます。
質問:T0ウェイクアップ時に、特別な指示なしにアレイの '更新された'ビューを取得する方法はありますか?
私たちは[STACK-REF]で述べられているような条件下で、巨大なint配列と多くのスレッドを含む、より複雑なテストを構築しました。毎回、スレッドT0(すなわち、「メイン」のスレッド)は、アレイの完全な一貫したビューを得た。
はい、私はその
Thread Caching and Java Memory model
主張知っている: 「各スレッドがメモリのローカルコピーを持っていません...」 が、答えは明らかに私たちの問題を説明していません。
@Basilevs
私はThread.join()が同期を行うことを期待しています。なぜあなたはそれを拒否しますか?
テストケースの初期バージョンを書くときは、Thread.join()ステートメントを使用しました。私は同じ結果を得た。
あなたのように、私は同期のためのjoin()リクエストを想像しました。私はこの仮説をテストするために、sleep()でjoin()を置き換えました。
...I'd recommend not to sleep while waiting ..., thread rescheduling is likely to synchronize thread's context of wake-up.
私はあなたと完全に同意します。 sleep()ステートメントがループに置き換えられました:
while(System.currentTimeMillis() - t0 < 2000);私はあなたの提案に基づいて新しいテストを投稿しました。
もう一度、矛盾は見られませんでした。
@Andrey Cheboksarov
(おっと、私は自分のPCを記述するために省略:!Win7の64-ビット、jdk8、procのインテルXeonプロセッサE5630)
...あなたはこの配列にいくつかの計算を行う場合その後、ほとんど常に更新された値
私はで活動中T1を保ち、それをテストが表示されますメインスレッドを、スレッド、バックグラウンドで停止o-opループ。 : あなたが正しいです。
... This will print something like -11 100 100 100 ...
右。
質問1:あなたの答えは他のプロセッサでも有効ですか?例:Power PC?
質問2:私のテストカスの結果がかなり正常であることを確認してください。
私は 'Thread.join()'が同期を実行することを期待しています。なぜあなたはそれを拒否しますか? – Basilevs
結果を待っている間にスリープ状態にならないように矛盾を観察するには、スレッドの再スケジューリングがスレッドのスリープ解除のコンテキストを同期させる可能性があります。 – Basilevs
可視性の保証は、保証された非可視性と同じではありません。キャッシュが無効にされている理由は多々ありますが、それらを第2に推測するのは、ほとんど無意味なものです。 – biziclop