Java 为什么这段代码不是线程安全的?

Java 为什么这段代码不是线程安全的?,java,scjp,Java,Scjp,在下面的代码段中,将doThings()方法声明为static将使类线程安全。这是因为如果启动多个TestSeven线程,并且由于x是一个静态变量,可能会发生争用情况吗 public class TestSeven extends Thread{ private static int x; public synchronized void doThings(){ int current = x; current++; x = c

在下面的代码段中,将doThings()方法声明为static将使类线程安全。这是因为如果启动多个TestSeven线程,并且由于x是一个静态变量,可能会发生争用情况吗

public class TestSeven extends Thread{

    private static int x;

    public synchronized void doThings(){
        int current = x;
        current++;
        x = current;
    }

    public void run(){
        doThings();
    }

    public static void main(String args[]){
        TestSeven t = new TestSeven();
        Thread thread = new Thread(t);
        thread.start();
    }
}

是的,没错。
doThings
synchronized
特性只会阻止同一实例上的多个线程同时调用它。变量
x
是在全局基础上共享的,而不是在每个实例的基础上共享的,因此它是不安全的


在现实世界中,把它想象成一个有多扇门的浴室——有人可以打开一扇门然后锁上,但这并不能阻止其他人从另一扇门进来……

我认为如果这个方法不是静态的,每个TestSeven对象都会使用自己的锁进行同步——所以每个锁都有一个线程,他们都不必等待另一个线程。如果该方法被声明为静态,我似乎记得它们锁定在相应的类对象上。

只是要补充一点,如果您声明方法是静态的,它将在类锁而不是实例锁上同步,因此它将是防弹的。

是的。在这种情况下可能会出现竞争条件。在使方法同步时,请不要使用变量。因此,根据竞争条件的定义,一个线程将读取变量的值,而同步方法中的另一个线程可以写入该值。因此会有一个竞争条件。

您在
上同步代码,这意味着在TestSeven的实例上
x
是静态的,因此它不会被锁定。这就是为什么您可以从不同的实例访问相同的
x
。为了在该属性上解除锁定,需要在类上进行同步

+1:锁定当前线程(这里就是这种情况)几乎总是毫无意义的。顺便说一句,您将TestSeven作为线程参数传递给线程构造函数。这是因为线程是可运行的,但不推荐这样做,您最好让TestSeven实现为可运行的