[英]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--;
}
}
谁能解释为什么上面的类不是线程安全的?
由于increment
方法是static
因此它将在ThreadSafeClass
的类对象上同步。 decrement
方法不是静态的,将在用于调用它的实例上同步。 即,它们将在不同的对象上同步,因此两个不同的线程可以同时执行这些方法。 由于++
和--
操作不是原子的,因此类不是线程安全的。
此外,由于count
是static
,因此将其作为同步实例方法的decrement
进行修改是不安全的,因为它可以在不同的实例上调用并以这种方式同时修改count
。
您有两个同步方法,但其中一个是静态的,另一个不是。 访问同步方法时,根据其类型(静态或非静态),将锁定其他对象。 对于静态方法,锁定将放在Class对象上,而对于非静态块,锁定将放在运行该方法的类的实例上。 因为您有两个不同的锁定对象,所以可以有两个线程同时修改同一个对象。
谁能解释为什么上面的类不是线程安全的?
increment
是静态的,同步将在类本身上完成。 decrement
不是静态的,则会在对象实例化上进行同步,但由于count
是静态的,因此不会保护任何内容。 我想添加它来声明一个线程安全的计数器,我相信最简单的方法是使用AtomicInteger
而不是原始的int。
让我将您重定向到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();
synchronized
上fun1
和fun2
是在实例对象的水平同步。 synchronized
上fun4
是在类对象电平同步。 意思是:
a1.fun1()
时,后一个调用将被阻止。 a1.fun1()
并且线程2同时调用a1.fun2()
时,后一个调用将被阻止。 a1.fun1()
并且线程2同时调用a1.fun3()
时,没有阻塞,这两个方法将同时执行。 A.fun4()
中,如果其他线程调用A.fun4()
或A.fun5()
在同一时间,后者的呼叫将被阻塞,因为synchronized
上fun4
是类级别。 A.fun4()
,线程2同时调用a1.fun1()
,没有阻塞,这两个方法将同时执行。 decrement
是锁定一个不同的东西来increment
所以它们不会阻止彼此运行。 decrement
是锁定在另一个实例上调用decrement
的另一个东西,但它们正在影响相同的事情。 第一个意味着重叠调用increment
和decrement
可能导致取消(正确),增量或减量。
第二个意味着两个重叠调用在不同实例上decrement
可能导致双递减(正确)或单个递减。
由于有两种不同的方法,一种是实例级别,另一种是类级别,因此需要锁定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();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.