从不同实例访问实例方法的多个线程应该导致竞争条件?

时间:2014-06-25 17:34:52

标签: java multithreading race-condition synchronized

我想了解Java中的同步。 我知道如果我从2个不同的线程访问同一个对象的同步方法,一次只能访问一个。

但我认为如果在2个不同的实例上调用相同的方法,则两个对象都应该能够并行访问该方法。如果从方法访问/修改静态成员变量,会导致竞争条件。但我无法在下面的代码中看到竞争状况。

有人可以解释一下代码或我的理解是否错误。

参考代码可在以下位置访问:http://ideone.com/wo6h4R

class MyClass
{
   public static int count=0;

   public  int getCount() 
   {

        System.out.println("Inside getcount()");
        return count;
   }

   public synchronized void incrementCount() 
   {
        count=count+1;
   }


}

class Ideone
{
    public static void main(String[] args) throws InterruptedException {
        final MyClass test1 = new MyClass();
        final MyClass test2 = new MyClass();
        Thread t1 = new Thread() { 
                                public void run()  
                                { 
                                    int k=0;
                                    while (k++<50000000)
                                    {
                                          test1.incrementCount();

                                    } 
                                }
                                };

    Thread t2 = new Thread() { 
                                public void run() 
                                { 
                                    int l=0;
                                    while (l++<50000000)
                                    {
                                            test2.incrementCount(); 

                                    } 
                                }
                                };

    t1.start();

    t2.start();
    t1.join();
    t2.join();
    //System.out.println(t2.getState());
    int x=500000000+500000000;
    System.out.println(x);
    System.out.println("count = " + MyClass.count);

}

}

3 个答案:

答案 0 :(得分:7)

你认为竞争条件存在是正确的。但是这些活动非常快,以至于它们不太可能发生 - synchronized关键字可能提供同步“帮助”,虽然JLS没有要求,但隐藏了比赛。

如果你想让它变得更加明显,你可以“拼出”count = count + 1代码并进入睡眠状态:

public synchronized void incrementCount() 
{
    int tmp = count + 1;
    try {
        Thread.sleep(500);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    count=tmp;
}

这应该更容易显示比赛。 (我对中断异常的处理对于生产代码有好处,顺便说一下;但对于像这样的小型测试应用来说它已经足够了。)

这里吸取的教训是:竞争条件可能很难通过测试,因此最好真正理解代码并向自己证明这是正确的。

答案 1 :(得分:0)

由于syncrhonized方法实际上在this上同步,因此不同的实例方法将锁定不同的对象,因此您将获得竞争条件,因为它们不会相互阻塞。

您可能必须制作自己的锁定对象并锁定它。

   class MyClass
    {
       public static int count=0;
           //this is what you lock on
       private static Object lock = new Object();

       public  int getCount() 
       {
           synchronized(lock){

                System.out.println("Inside getcount()");
                return count;
           }
       }

       public void incrementCount() 
       {
           synchronized(lock){
               count = count+1;
           }

       }
          //etc

现在,当您运行主程序时,会打印出来:

1000000000
count = 100000000

答案 2 :(得分:0)

以下是Java specification的相关部分:

“synchronized方法在执行之前获取监视器(第17.1节)。对于类(静态)方法,使用与方法类的Class对象关联的监视器。对于实例方法,与此关联的监视器(使用该方法的对象)。“

但是我没有看到MyClass的实例在哪里实际递增“计数”所以你期望将什么显示为竞争条件?

Taken originally from this answer