为什么这个类不是线程安全的?

class ThreadSafeClass extends Thread { private static int count = 0; public synchronized static void increment() { count++; } public synchronized void decrement() { count--; } } 

任何人都可以解释为什么以上类不是线程安全的?

由于increment方法是static ,它将同步在ThreadSafeClass的类对象上。 decrement方法不是静态的,将在用于调用它的实例上同步。 也就是说,它们将在不同的对象上进行同步,因此两个不同的线程可以同时执行这些方法。 由于++--操作不是primefaces的,所以类不是线程安全的。

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

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

任何人都可以解释为什么以上类不是线程安全的?

  • increment是静态的,同步将在类本身完成。
  • decrement不是静态的,同步将在对象实例化上完成,但是由于count是静态的,所以不能保证任何东西。

我想补充说,声明一个线程安全的计数器,我相信最简单的方法是使用AtomicInteger而不是原始的int。

让我redirect到java.util.concurrent.atomic包信息。

  1. decrementlocking在不同的东西上increment所以它们不会阻止对方运行。
  2. 在一个实例上调用decrement是locking在另一个事件上调用另一个实例上的decrement ,但它们影响同一件事情。

第一种意思是重叠调用incrementdecrement可能会导致取消(正确),增量或减量。

第二个意思是两个重叠的调用在不同的实例上decrement会导致双重递减(正确)或单个递减。

其他人的回答很好解释了原因。 我只是添加一些总结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 fun1fun2在实例对象级同步。 synchronized fun4在类对象级同步。 意思是:

  1. 当两个线程同时调用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() ,后面的调用将被阻塞,因为fun4上的synchronized是类层次的。
  5. 当线程1调用A.fun4() ,线程2同时调用a1.fun1() ,不阻塞,同时执行2个方法。

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

正如其他答案中所解释的,你的代码不是线程安全的,因为静态方法increment()locking类监视器和非静态方法decrement()锁对象监视器。

对于这个代码示例,没有synchronzed关键字用法存在更好的解决scheme 你必须使用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(); } }