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

时间:2011-11-25 11:09:52

标签: java scjp

在下面的代码片段中,将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();
    }
}

5 个答案:

答案 0 :(得分:16)

是的,确切地说。 synchronized的{​​{1}}性质仅阻止多个线程同时在同一个实例上调用它。变量doThings全局的基础上共享,而不是基于每个实例,因此它不安全。

在现实世界中,把它想象成一个有几个门的浴室 - 有人可以打开一扇门然后将其锁上,但这并不能阻止其他人通过不同的门进来...

答案 1 :(得分:1)

我认为如果该方法不是静态的,则每个TestSeven对象将使用自己的锁进行同步 - 因此每个锁将有一个线程,并且它们都不必等待另一个线程。如果该方法被声明为static,我似乎记得它们锁定了相应的Class对象。

答案 2 :(得分:1)

只是要补充一点,如果你声明方法doThings是静态的,它将在类锁上而不是实例锁同步,这样就可以防弹了。

答案 3 :(得分:1)

是肯定的。这种情况可能会发生。正如您使方法同步而不是您的变量。因此根据竞争条件的定义,一个线程将读取变量的值,而其他同步方法可以写入它。因此会出现竞争条件。

答案 4 :(得分:1)

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