5

以下に簡単な例を示します。

private long counter = 0;

// note this method is NOT synchronized
// this will be called by thread A
public void increment() { counter++; }

// note this method IS synchronized
// this will be called by thread B
public synchronized long value() { return counter; }

counterしたがって、変数は不揮発性であるため、CPUキャッシュにスタックされた値ではなく、の適切な値を取得したいだけです。目標は、カウンターを揮発性にしないことです。そのため、インクリメントを行うスレッド A には影響しませんが、変数を読み取るときに気にしないスレッド B のみに影響します。

記録のために、counterスレッド A がとにかく終了したときに、スレッド B から の値を読み取る予定です...

4

4 に答える 4

3

いいえ、スレッド B の同期ブロックは、 の実際の現在の値を読み取ることを保証しませんcounter。これを行うには、両方のスレッドでブロックを同期する必要があります。実際的な観点から、コードは、スレッド B を実行しているプロセッサがそのキャッシュを無効にし、メイン メモリから の値を読み取ることをcounter保証しますが、スレッド A を実行しているプロセッサがその現在の値をメイン メモリにフラッシュすることを保証しません。メモリが古い可能性があります。

volatile 変数を使用すると、両方のスレッドで同期ブロックよりもコストがかからないため、volatile にすることcounterが正しい解決策である可能性があります。これが揮発性変数の目的です。

編集: スレッド B が最終値を読み取る前にスレッド A が完了する場合は、スレッド A の実行全体を単一の同期ブロックで囲むか、カウンターを読み取る前にスレッド B をスレッド A に参加させて、スレッド A が最終値の前に完了するようにすることができます。カウンターが読み取られます。これにより、スレッド A の実行の最後に 1 回のキャッシュ フラッシュが発生しますが、パフォーマンスへの影響はほとんどありません。

于 2014-03-28T07:36:02.797 に答える
2

long割り当てはアトミックであることが保証されていないため、B は古い値を読み取るだけでなく、半分書き込まれた値を読み取ることもできます。

適切な可視性を得るには、カウンターを揮発性にする必要があります。その場合でも、いくつかのスレッドからインクリメントを n 回呼び出しても、カウンターが n ずつインクリメントされない場合があることに注意してください。

問題があるので、 to を使用できAtomicLongます。

于 2014-03-28T07:35:08.120 に答える
0

Thread Bいいえ。常に最新の値を返す保証はありませんincrement()。非同期メソッドで、value()は同期メソッドなので。
以来

スレッドがオブジェクトの同期メソッド内にある間、この同期メソッドまたはオブジェクトの他の同期メソッドを実行しようとする他のすべてのスレッドは待機する必要があります。

この制限は、既にロックを保持しており、オブジェクトの同期メソッドを実行しているスレッドには適用されません。このようなメソッドは、ブロックされることなく、オブジェクトの他の同期メソッドを呼び出すことができます。もちろん、オブジェクトの非同期メソッドは、任意のスレッドからいつでも呼び出すことができます。

于 2014-03-28T07:36:41.987 に答える