为什么这个 class 不是线程安全的?
Why is this class not thread safe?
class ThreadSafeClass extends Thread
{
private static int count = 0;
public synchronized static void increment()
{
count++;
}
public synchronized void decrement()
{
count--;
}
}
谁能解释为什么上面 class 不是线程安全的?
由于 increment
方法是 static
,它将在 ThreadSafeClass
的 class 对象上同步。 decrement
方法不是静态的,它将在用于调用它的实例上同步。也就是说,它们将在不同的对象上同步,因此两个不同的线程可以同时执行这些方法。由于 ++
和 --
操作不是原子操作,因此 class 不是线程安全的。
此外,由于 count
是 static
,从 decrement
修改它是一个同步的 instance 方法是不安全的,因为它可以调用不同的实例并以这种方式同时修改 count
。
您有两个同步方法,但其中一个是静态的,另一个不是。当访问同步方法时,根据它的类型(静态或非静态),不同的对象将被锁定。对于静态方法,将在 Class 对象上加锁,而对于非静态块,将在运行该方法的 class 实例上加锁。因为你有两个不同的锁定对象,所以你可以有两个线程同时修改同一个对象。
由于两种不同的方法,一种是实例级别,另一种是class级别,所以你需要锁定2个不同的对象以使其成为ThreadSafe
decrement
锁定的是与 increment
不同的东西,因此它们不会互相阻止 运行.
- 在一个实例上调用
decrement
与在另一个实例上调用 decrement
锁定不同的东西,但它们影响的是同一件事。
第一个意思是重叠调用 increment
和 decrement
可能会导致取消(正确)、增加或减少。
第二个意味着在不同的实例上对 decrement
的两次重叠调用可能会导致双重递减(正确)或一次递减。
Can anyone explain why above class is not thread safe?
increment
是静态的,同步将在 class 本身上完成。
decrement
不是静态的,同步将在对象实例化上完成,但这并不能保护任何东西,因为 count
是静态的。
我想添加它来声明线程安全计数器,我相信最简单的方法是使用 AtomicInteger
而不是原始 int。
让我将您重定向到 java.util.concurrent.atomic
软件包信息。
其他人的回答很好解释了原因。我只是添加一些总结 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();
synchronized
在 fun1
和 fun2
上在实例对象级别同步。 fun4
上的 synchronized
在 class 对象级别同步。这意味着:
- 当2个线程同时调用
a1.fun1()
时,后面的调用会被阻塞
- 当线程1调用
a1.fun1()
和线程2同时调用a1.fun2()
时,后面的调用会被阻塞
- 当线程1调用
a1.fun1()
和线程2同时调用a1.fun3()
时,无阻塞,2个方法会同时执行
- 当线程1调用
A.fun4()
时,如果其他线程同时调用A.fun4()
或A.fun5()
,后面的调用将被阻塞,因为synchronized
在fun4
是class级。
- 当线程1调用
A.fun4()
时,线程2同时调用a1.fun1()
,不阻塞,2个方法会同时执行
如其他答案中所述,您的代码 不是线程安全的 因为静态方法 increment()
锁定 Class 监视器和非静态方法 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();
}
}
class ThreadSafeClass extends Thread
{
private static int count = 0;
public synchronized static void increment()
{
count++;
}
public synchronized void decrement()
{
count--;
}
}
谁能解释为什么上面 class 不是线程安全的?
由于 increment
方法是 static
,它将在 ThreadSafeClass
的 class 对象上同步。 decrement
方法不是静态的,它将在用于调用它的实例上同步。也就是说,它们将在不同的对象上同步,因此两个不同的线程可以同时执行这些方法。由于 ++
和 --
操作不是原子操作,因此 class 不是线程安全的。
此外,由于 count
是 static
,从 decrement
修改它是一个同步的 instance 方法是不安全的,因为它可以调用不同的实例并以这种方式同时修改 count
。
您有两个同步方法,但其中一个是静态的,另一个不是。当访问同步方法时,根据它的类型(静态或非静态),不同的对象将被锁定。对于静态方法,将在 Class 对象上加锁,而对于非静态块,将在运行该方法的 class 实例上加锁。因为你有两个不同的锁定对象,所以你可以有两个线程同时修改同一个对象。
由于两种不同的方法,一种是实例级别,另一种是class级别,所以你需要锁定2个不同的对象以使其成为ThreadSafe
decrement
锁定的是与increment
不同的东西,因此它们不会互相阻止 运行.- 在一个实例上调用
decrement
与在另一个实例上调用decrement
锁定不同的东西,但它们影响的是同一件事。
第一个意思是重叠调用 increment
和 decrement
可能会导致取消(正确)、增加或减少。
第二个意味着在不同的实例上对 decrement
的两次重叠调用可能会导致双重递减(正确)或一次递减。
Can anyone explain why above class is not thread safe?
increment
是静态的,同步将在 class 本身上完成。decrement
不是静态的,同步将在对象实例化上完成,但这并不能保护任何东西,因为count
是静态的。
我想添加它来声明线程安全计数器,我相信最简单的方法是使用 AtomicInteger
而不是原始 int。
让我将您重定向到 java.util.concurrent.atomic
软件包信息。
其他人的回答很好解释了原因。我只是添加一些总结 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();
synchronized
在 fun1
和 fun2
上在实例对象级别同步。 fun4
上的 synchronized
在 class 对象级别同步。这意味着:
- 当2个线程同时调用
a1.fun1()
时,后面的调用会被阻塞 - 当线程1调用
a1.fun1()
和线程2同时调用a1.fun2()
时,后面的调用会被阻塞 - 当线程1调用
a1.fun1()
和线程2同时调用a1.fun3()
时,无阻塞,2个方法会同时执行 - 当线程1调用
A.fun4()
时,如果其他线程同时调用A.fun4()
或A.fun5()
,后面的调用将被阻塞,因为synchronized
在fun4
是class级。 - 当线程1调用
A.fun4()
时,线程2同时调用a1.fun1()
,不阻塞,2个方法会同时执行
如其他答案中所述,您的代码 不是线程安全的 因为静态方法 increment()
锁定 Class 监视器和非静态方法 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();
}
}