我想了解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);
}
}
答案 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的实例在哪里实际递增“计数”所以你期望将什么显示为竞争条件?