Javaでの複数のスレッドの同期をより完全に理解しようとしています。私は、synchronizedキーワードの使用の背後にある高レベルのアイデアと、それがスレッド間の相互排除をどのように提供するかを理解しています。
唯一のことは、私がオンラインで読んだ教科書の例のほとんどは、同期されたキーワードを削除しても正しく機能することです。これにより、このトピックが必要以上に混乱します。
同期キーワードを含めないと誤った結果が生じる具体的な例を誰かに教えてもらえますか?どんな情報でも大歓迎です。
Javaでの複数のスレッドの同期をより完全に理解しようとしています。私は、synchronizedキーワードの使用の背後にある高レベルのアイデアと、それがスレッド間の相互排除をどのように提供するかを理解しています。
唯一のことは、私がオンラインで読んだ教科書の例のほとんどは、同期されたキーワードを削除しても正しく機能することです。これにより、このトピックが必要以上に混乱します。
同期キーワードを含めないと誤った結果が生じる具体的な例を誰かに教えてもらえますか?どんな情報でも大歓迎です。
競合状態については、適切な同期を行わないと必ずしも発生しないということです。実際、かなり頻繁に正常に機能しますが、1年後の深夜にコードが発生します。バグはランダムにしか発生しないため、再現できない完全に予測不可能なバグでクラッシュします。
競合状態は、プログラムを常にクラッシュさせるとは限らず、多かれ少なかれランダムにトリガーされるため、非常に陰湿です。
通常、反復回数を増やすことで競合状態をトリガーできます。これは、100回と1,000回の反復で機能するが、10,000回の反復(場合によっては)で失敗する(少なくとも私のクアッドコアボックスでは)簡単な例です。
public class Race
{
static final int ITERATIONS = 10000;
static int counter;
public static void main(String[] args) throws InterruptedException {
System.out.println("start");
Thread first = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < ITERATIONS; i++) {
counter++;
}
}
});
Thread second = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < ITERATIONS; i++) {
counter++;
}
}
});
first.start();
second.start();
first.join();
second.join();
System.out.println("Counter " + counter + " should be " + (2 * ITERATIONS));
}
}
>>> Counter 12325 should be 20000
counter
アクセスが適切に同期されていないため、この例は失敗します。2つの方法で失敗する可能性があり、同じ実行で両方が失敗する可能性があります。
この単純なプログラムの修正は、を使用することAtomicInteger
です。インクリメントの問題があるため、使用volatile
するだけでは不十分ですがAtomicInteger
、インクリメント、取得および設定などのアトミック操作を提供します。