繁体   English   中英

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

[英]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方法不是静态的,将在用于调用它的实例上同步。 即,它们将在不同的对象上同步,因此两个不同的线程可以同时执行这些方法。 由于++--操作不是原子的,因此类不是线程安全的。

此外,由于countstatic ,因此将其作为同步实例方法的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();

synchronizedfun1fun2是在实例对象的水平同步。 synchronizedfun4是在类对象电平同步。 意思是:

  1. 当2个线程同时调用a1.fun1()时,后一个调用将被阻止。
  2. 当线程1调用a1.fun1()并且线程2同时调用a1.fun2()时,后一个调用将被阻止。
  3. 当线程1调用a1.fun1()并且线程2同时调用a1.fun3()时,没有阻塞,这两个方法将同时执行。
  4. 当线程1呼叫A.fun4()中,如果其他线程调用A.fun4()A.fun5()在同一时间,后者的呼叫将被阻塞,因为synchronizedfun4是类级别。
  5. 当线程1调用A.fun4() ,线程2同时调用a1.fun1() ,没有阻塞,这两个方法将同时执行。
  1. decrement是锁定一个不同的东西来increment所以它们不会阻止彼此运行。
  2. 在一个实例上调用decrement是锁定在另一个实例上调用decrement的另一个东西,但它们正在影响相同的事情。

第一个意味着重叠调用incrementdecrement可能导致取消(正确),增量或减量。

第二个意味着两个重叠调用在不同实例上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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM