5

Java を介した同期について学ぶために、スレッド間で共有されるカウンターの作成など、いくつかの簡単なことをいじっています。

私が遭遇した問題は、カウンターを 100% 連続して印刷する方法がわからないことです。

int counterValue = this.counter.incrementAndGet();
System.out.println(this.threadName + ": " + counterValue);

上記は をインクリメントしAtomicInteger counter、新しい値を取得して、その更新を担当するスレッド名で識別されるコンソールに出力します。この問題はincrementAndGet()、現在のスレッドの更新された値を出力する前に、JVM がその更新のために別のスレッドにコンテキスト スイッチを行っているように見える場合に発生します。これは、スレッドが実行状態に戻るまで、値がインクリメントされても出力されないことを意味します。これは、次の出力例を見ると明らかです。

Thread 3: 4034
Thread 3: 4035
Thread 3: 4036
Thread 1: 3944
Thread 1: 4037
Thread 1: 4039
Thread 1: 4040
Thread 2: 3863
Thread 1: 4041
Thread 1: 4043

実行がスレッド 1 に戻ると、その値が出力され、更新が続行されることがわかります。同じことがスレッド 2 でも明らかです。

非常に明白な何かが欠けているような気がします。

4

3 に答える 3

1

順次印刷するには、incAndGetとprintlnの両方がクリティカル領域にある必要があります。1つのスレッドのみが入力できるコードの一部であり、他のスレッドはブロックされます。たとえば、javaのようなバイナリセマフォで実現できますsynchronized

あなたは頭の上で物事を回して、1つのスレッドでカウンターをインクリメントしてそれを印刷することができます。「クリティカル領域」にある他のスレッドは、次々にカウンターを取得する場合があります。重要な領域は小さいままで、I / Oを行わないことが望ましいため、これはより効率的です。

于 2012-04-09T18:42:52.430 に答える
1

そのためには、構築全体を同期する必要があります。

synchronized(this) {    
   int counterValue = this.counter.incrementAndGet();
   System.out.println(this.threadName + ": " + counterValue);
}

ただし、この場合、AtomicInteger を使用する必要はありません。プレーンintで動作します(カウンター++)。

于 2012-04-09T18:38:43.303 に答える