实例和静态方法的并发性测试的有效性

时间:2010-12-15 02:05:20

标签: java multithreading concurrency

我想验证我编写的以下测试,以验证两个线程可以同时访问静态同步方法和非静态同步方法(因为锁在不同对象上)这一事实。我得到了一个结果,但想知道我的解释是否正确

我运行下面的代码,我看到变量i的相同值分别来自静态和非静态方法。这是静态和非静态方法对两个不同对象具有锁定的事实的有效证明,并且两个线程可以同时访问它们。

代码

import java.util.ArrayList;
import java.util.List;

public class TestStaticSynchronize {

public static final TesteeClass obj = new TesteeClass();

/**
 * @param args
 */
public static void main(String[] args) {
    for(int i = 0; i < 50; i++) {
        Runner run = new Runner(i);
        Thread th = new Thread(run);
        th.start();
    }
}

static class Runner implements Runnable {

    private int i;

    public Runner(int i) {
        this.i = i;
    }

    public void run() {
        if(i % 2 == 0) {
            TesteeClass.staticSync();
        } else {
            obj.instanceSync();
        }
    }

}
}

class TesteeClass {

private static List<Integer> testList = new ArrayList<Integer>();


public static synchronized void staticSync() {
    System.out.println("Reached static synchronized method " + testList.size()); 
    testList.add(1);
}

public synchronized void instanceSync() {
    System.out.println("Reach instance synchronized method " + testList.size());  
    testList.add(1);
}
}

1 个答案:

答案 0 :(得分:1)

您的评估是正确的。这就是原因。

因此,请使用您的synchronized实例方法,并以等效的同步块表示法重写它:

public void instanceSync() {
    synchronized( this ) {
        System.out.println("...");
        testList.add( 1 );
    }
}

当你编写同步方法时,它与锁定周围实例(即这个)是一回事。使用静态方法,此参数不存在,那么静态的等效同步块是什么?它锁定了Class对象。

public void classSync() {
   synchronized( TestClass.class ) {
       System.out.println("...");
       testList.add( 1 );
   }
}

因此实例这是与表示TestClass类的对象不同的对象。这意味着使用了两个不同的锁,这会导致您发现的问题。最后,您的测试程序非常危险,而且不是线程安全的。实例方法,尤其是在多线程情况下使用时,不应该触及静态成员周期。通过静态方法来路由这些访问是很好的,但是直接访问最好是一个糟糕的错误形式。

有一种方法可以以一种锁定同一对象的方式编写程序,但我认为你考虑为什么要编写这样的代码是很重要的。是因为你真的只想要很多地方共享这样的单一结构,但却无法获得对单个对象的引用?这是软件架构的核心,也是它在多线程应用程序中扮演的重要角色。我怀疑有一个比使用静态成员更好的选择,并且只使用一个所有位置都有引用的实例(希望不使用单例模式,全局静态等)。