class ThreadSafeClass extends Thread
{
private static int count = 0;
public synchronized static void increment()
{
count++;
}
public synchronized void decrement()
{
count--;
}
}
上記のクラスがスレッドセーフではない理由を誰でも説明できますか?
increment
メソッドはstatic
であるため、ThreadSafeClass
のクラスオブジェクトで同期します。 decrement
メソッドは静的ではなく、呼び出しに使用されたインスタンスで同期します。つまり、異なるオブジェクトで同期するため、2つの異なるスレッドが同時にメソッドを実行できます。 ++
および--
操作はアトミックではなく、クラスはスレッドセーフではありません。
また、count
はstatic
であるため、同期instanceメソッドであるdecrement
から変更すると、異なるインスタンスで呼び出すことができ、 count
を同時にそのように変更します。
2つの同期メソッドがありますが、一方は静的で、もう一方はそうではありません。タイプ(静的または非静的)に基づいて同期メソッドにアクセスすると、別のオブジェクトがロックされます。静的メソッドの場合、Classオブジェクトにロックがかけられ、非静的ブロックの場合、メソッドを実行するクラスのインスタンスにロックがかけられます。 2つの異なるロックされたオブジェクトがあるため、同じオブジェクトを同時に変更する2つのスレッドを持つことができます。
上記のクラスがスレッドセーフではない理由を誰でも説明できますか?
increment
は静的であるため、同期はクラス自体で行われます。decrement
は静的ではないため、オブジェクトのインスタンス化で同期が行われますが、count
は静的であるため、何も保護されません。それを追加して、スレッドセーフカウンターを宣言します。最も簡単な方法は、プリミティブなintの代わりに AtomicInteger
を使用することです。
Java.util.concurrent.atomic
package-info。
他の人の答えはその理由を説明するのにかなり良いです。要約を追加するだけでsynchronized
:
public class A {
public synchronized void fun1() {}
public synchronized void fun2() {}
public void fun3() {}
public static synchronized void fun4() {}
public static void fun5() {}
}
A a1 = new A();
fun1
およびfun2
上のsynchronized
は、インスタンスオブジェクトレベルで同期されます。 fun4
のsynchronized
は、クラスオブジェクトレベルで同期されます。つまり:
a1.fun1()
を同時に呼び出すと、後者の呼び出しはブロックされます。a1.fun1()
を呼び出し、スレッド2がa1.fun2()
を同時に呼び出すと、後者の呼び出しはブロックされます。a1.fun1()
を呼び出し、スレッド2がa1.fun3()
を同時に呼び出した場合、ブロッキングは発生せず、2つのメソッドが同時に実行されます。A.fun4()
を呼び出すとき、他のスレッドがA.fun4()
またはA.fun5()
を同時に呼び出すと、fun4
のsynchronized
はクラスであるため、後者の呼び出しはブロックされますレベル。A.fun4()
を呼び出し、スレッド2がa1.fun1()
を同時に呼び出し、ブロッキングが発生しない場合、2つのメソッドが同時に実行されます。decrement
はincrement
とは異なるものをロックしているため、お互いの実行を妨げません。decrement
を呼び出すことは、別のインスタンスでdecrement
を呼び出すこととは異なることをロックしますが、同じことに影響を及ぼします。最初の意味は、increment
とdecrement
の呼び出しが重複すると、キャンセル(正しい)、増分、または減分になる可能性があることを意味します。
2番目は、異なるインスタンスでdecrement
を2回重複して呼び出すと、二重のデクリメント(正しい)または単一のデクリメントが発生する可能性があることを意味します。
2つの異なるメソッド、1つはインスタンスレベル、もう1つはクラスレベルであるため、2つの異なるオブジェクトをロックしてThreadSafeにする必要があります。
他の回答で説明したように、静的メソッドincrement()
はクラスモニターと非静的メソッドdecrement()
オブジェクトモニターをロックします。
このコード例では、synchronzed
キーワードを使用せずに、より良いソリューションが存在します。スレッドの安全性を実現するには、 AtomicInteger を使用する必要があります。
AtomicInteger
を使用したスレッドセーフ:
import Java.util.concurrent.atomic.AtomicInteger;
class ThreadSafeClass extends Thread {
private static AtomicInteger count = new AtomicInteger(0);
public static void increment() {
count.incrementAndGet();
}
public static void decrement() {
count.decrementAndGet();
}
public static int value() {
return count.get();
}
}