1

この Java クラスはスレッド セーフですか、それともリセット メソッドも同期する必要がありますか? はいの場合、誰かがその理由を教えてもらえますか?

public class NamedCounter {
   private int count;
   public synchronized void increment() { count++; }
   public synchronized int getCount() { return count; }
   public void reset() { count = 0; }
}
4

5 に答える 5

8

rest() を同期し、さらにメソッドを追加しないわけではありません。より多くのメソッドが必要になる場合があります。例えば

NamedCounter counter = new NamedCounter();
counter.increment();
// at this exact time (before reaching the below line) another thread might change changed the value of counter!!!!
if(counter.getCount() == 1) {
    //do something....this is not thread safe since you depeneded on a value that might have been changed by another thread
}

上記を修正するには、次のようなものが必要です

NamedCounter counter = new NamedCounter();
if(counter.incrementAndGet()== 1) { //incrementAndGet() must be a synchronized method
    //do something....now it is thread safe
}

代わりに、すべてのケースをカバーする Java の組み込みクラス AtomicInteger を使用してください。または、スレッドセーフを学習しようとしている場合は、AtomicInteger を標準として (学習するために) 使用してください。

プロダクション コードの場合は、よく考えずに AtomicInteger を使用してください。AtomicInteger を使用しても、コードのスレッド セーフが自動的に保証されるわけではないことに注意してください。API によって提供されるメソッドを使用する必要があります。彼らは理由があってそこにいます。

于 2013-07-04T08:36:39.687 に答える
2

相互排除だけsynchronizedでなく、基本的に、アクションの可視性という観点から、操作の適切な順序付けに関するものであることに注意してください。したがって、同期も行う必要があります。そうしないと、書き込みが他の 2 つのメソッドに対して同時に発生する可能性があり、表示される保証がありません。reset

結論として、クラスはそのままではスレッドセーフではありませんが、resetメソッドを同期するとすぐにスレッドセーフになります。

于 2013-07-04T08:33:51.033 に答える
1

reset()メソッドも同期する必要があります。

classスレッド セーフにするには、変数にアクセスするすべてのパスを同期する必要があります。そうしないと、同期されていないパスで望ましくない結果が生じます。

于 2013-07-04T08:36:42.210 に答える
0

Synchronized to reset メソッドも追加する必要があり、その後同期されます。ただし、この方法では、ロックを使用して同期を実現します。つまり、メソッドにアクセスする各スレッドは NamedCounter オブジェクトのインスタンスをロックします。

ただし、カウント変数として AtomicInteger を使用する場合は、CAS CPU 操作を使用して同期する必要なく原子性を実現するため、同期する必要はもうありません。

于 2013-07-04T08:34:47.170 に答える