2

私は Java のマルチスレッドに不慣れで、何が起こっているのかよくわかりません。

オンライン チュートリアルと講義ノートから、synchronizednull 以外のオブジェクトに適用する必要があるブロックにより、1 つのスレッドのみがそのコード ブロックを実行できることが保証されることがわかりました。配列は Java のオブジェクトであるため、同期を適用できます。さらに、配列にオブジェクトが格納されている場合、配列の各要素も同期できるはずです。

Long私のプログラムにはいくつかのスレッドが数値の配列を更新しているため、オブジェクトの配列を作成しました。

synchronized (grid[arrayIndex]){
    grid[arrayIndex] += a.getNumber();
}

このコードはrun()、私が拡張したスレッド クラスのメソッド内にあります。配列、グリッドは、すべてのスレッドで共有されています。ただし、1 つのスレッドで同じプログラムを実行している場合、これは正しい結果を返しません。

4

4 に答える 4

7

これは機能しません。grid[arrayIndex] += ...実際には の要素をgrid新しいオブジェクトに置き換えていることを理解することが重要です。これは、配列内のオブジェクトを同期し、すぐにそのオブジェクトを配列内の別のオブジェクトに置き換えることを意味します。これにより、他のスレッドが別のオブジェクトをロックするため、ブロックされません。定数オブジェクトをロックする必要があります。

別の配列オブジェクトに置き換えられない場合は、代わりに配列オブジェクト全体をロックできます。

synchronized (grid) {
    // this changes the object to another Long so can't be used to lock
    grid[arrayIndex] += a.getNumber();
}

finalこれが、オブジェクトをロックするのに適したパターンである理由の 1 つです。詳細については、この回答を参照してください。

Boolean で同期することが適切でないのはなぜですか?

于 2012-09-06T16:40:35.100 に答える
2

別のオプションは、AtomicLongオブジェクトの配列を使用し、それらのaddAndGet()orgetAndAdd()メソッドを使用することです。オブジェクトをインクリメントするために同期は必要なく、複数のオブジェクトを同時にインクリメントできます。

于 2012-09-06T16:43:43.890 に答える
1

Java クラス Long は不変であり、その値を変更することはできません。したがって、アクションを実行すると:

grid[arrayIndex] += a.getNumber();

ロックしている grid[arrayIndex] の値を変更するのではなく、実際には新しい Long オブジェクトを作成し、その値を古い値に a.getNumber を加えた値に設定しています。そのため、さまざまなオブジェクトで同期するさまざまなスレッドが発生し、結果が表示されます。

于 2012-09-06T16:48:53.567 に答える
0

ここsynchronizedにあるブロックはダメです。おそらく数値である配列要素を同期する場合、そのオブジェクトのみを同期しています。配列の要素を最初に使用したオブジェクトとは異なるオブジェクトに再割り当てすると、同期は正しいオブジェクトではなくなり、他のスレッドがそのインデックスにアクセスできるようになります。

次の 2 つのオプションのいずれかがより正確です。

private final int[] grid = new int[10];

synchronized (grid) {
    grid[arrayIndex] += a.getNumber();
}

gridできない場合final

private final Object MUTEX = new Object();

synchronized (MUTEX) {
    grid[arrayIndex] += a.getNumber();
}

2 番目のオプションを使用し、 でgridはないfinal場合、 への割り当てgridも同期する必要があります。

synchronized (MUTEX) {
    grid = new int[20];
}

常に最終的なもので同期し、常にアクセスと変更の両方で同期します。それができたら、 、 、 などの他のロック メカニズムを調べ始めることがLockできReadWriteLockますSemaphoreこれらは同期よりも複雑なロック メカニズムを提供でき、高スループット システムでのデータのロック (読み取り/書き込みロック) やリソース プールでのロック (セマフォのカウント)など、Java の既定の同期だけでは不十分なシナリオに適しています。

于 2012-09-06T16:47:12.177 に答える