为什么这个 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 不是线程安全的。

此外,由于 countstatic,从 decrement 修改它是一个同步的 instance 方法是不安全的,因为它可以调用不同的实例并以这种方式同时修改 count

您有两个同步方法,但其中一个是静态的,另一个不是。当访问同步方法时,根据它的类型(静态或非静态),不同的对象将被锁定。对于静态方法,将在 Class 对象上加锁,而对于非静态块,将在运行该方法的 class 实例上加锁。因为你有两个不同的锁定对象,所以你可以有两个线程同时修改同一个对象。

由于两种不同的方法,一种是实例级别,另一种是class级别,所以你需要锁定2个不同的对象以使其成为ThreadSafe

  1. decrement 锁定的是与 increment 不同的东西,因此它们不会互相阻止 运行.
  2. 在一个实例上调用 decrement 与在另一个实例上调用 decrement 锁定不同的东西,但它们影响的是同一件事。

第一个意思是重叠调用 incrementdecrement 可能会导致取消(正确)、增加或减少。

第二个意味着在不同的实例上对 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();

synchronizedfun1fun2 上在实例对象级别同步。 fun4 上的 synchronized 在 class 对象级别同步。这意味着:

  1. 当2个线程同时调用a1.fun1()时,后面的调用会被阻塞
  2. 当线程1调用a1.fun1()和线程2同时调用a1.fun2()时,后面的调用会被阻塞
  3. 当线程1调用a1.fun1()和线程2同时调用a1.fun3()时,无阻塞,2个方法会同时执行
  4. 当线程1调用A.fun4()时,如果其他线程同时调用A.fun4()A.fun5(),后面的调用将被阻塞,因为synchronizedfun4是class级。
  5. 当线程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();
    }

}