我想验证我编写的以下测试,以验证两个线程可以同时访问静态同步方法和非静态同步方法(因为锁在不同对象上)这一事实。我得到了一个结果,但想知道我的解释是否正确
我运行下面的代码,我看到变量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);
}
}
答案 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类的对象不同的对象。这意味着使用了两个不同的锁,这会导致您发现的问题。最后,您的测试程序非常危险,而且不是线程安全的。实例方法,尤其是在多线程情况下使用时,不应该触及静态成员周期。通过静态方法来路由这些访问是很好的,但是直接访问最好是一个糟糕的错误形式。
有一种方法可以以一种锁定同一对象的方式编写程序,但我认为你考虑为什么要编写这样的代码是很重要的。是因为你真的只想要很多地方共享这样的单一结构,但却无法获得对单个对象的引用?这是软件架构的核心,也是它在多线程应用程序中扮演的重要角色。我怀疑有一个比使用静态成员更好的选择,并且只使用一个所有位置都有引用的实例(希望不使用单例模式,全局静态等)。