我很难理解同步如何在来自同一对象的两种不同方法上工作。 我有一个类,其中有两个实例方法被声明为已同步。 三个线程访问该对象的两个同步方法,但结果出乎意料。线程可互换地访问这两种方法。他们不等待整个对象的锁定被释放。 这是示例:
public class ThreadSafeCounterSameMonitor2 {
private int value;
public synchronized int getValue() {
return this.value;
}
public synchronized void setValue(int value) {
this.value = value;
}
public static void main(String[] args) {
ThreadSafeCounterSameMonitor2 nts = new ThreadSafeCounterSameMonitor2();
Thread th1 = new Thread(new Runnable() {
public void run() {
nts.setValue(5);
System.out.println("Thread Id " + Thread.currentThread().getId() + ", expected value is 5, value=" + nts.getValue());
}
});
Thread th2 = new Thread(new Runnable() {
public void run() {
nts.setValue(10);
System.out.println("Thread Id " + Thread.currentThread().getId() + ", expected value is 10, value="
+ nts.getValue());
}
});
Thread th3 = new Thread(new Runnable() {
public void run() {
nts.setValue(15);
System.out.println("Thread Id " + Thread.currentThread().getId() + ", expected value is 15, value="
+ nts.getValue());
}
});
th1.start();
th2.start();
th3.start();
}
}
我得到的结果令人惊讶:
Thread Id 13, expected value is 15, value=15.
Thread Id 12, expected value is 10, value=15.
Thread Id 11, expected value is 5, value=15.
所以,我原本期望10的地方是15。我原本期望5的地方还是15。
我的理解是,监视器中所有同步方法在被线程访问时都会被锁定。但事实并非如此。在线程的同一run()方法中,我设置了一个值,然后检索它,它给了我另一个从另一个线程更改的值。
我经常读到类似“同步方法在此引用上获取隐式锁”之类的内容,但这显然是不正确的,即使对于同一监视器中的所有方法同步方法也是如此。还是我在代码中做得不好?
我的问题是,如何才能真正锁定整个对象的同步方法?您知道一个可以很好地解释这个概念的教程吗?
答案 0 :(得分:5)
这里没有不可预测的结果。并且同步正常工作。问题是您先调用方法setValue()
,然后再调用getValue()
。在您的示例线程中,线程以这种方式重叠,即在其他线程调用setValue()
之后但在任何线程调用getValue()
之前设置值15。
您可以在第三个线程的Thread.sleep(1000)
方法中添加run()
,以查看结果可能会发生变化。
同步方法获得对对象的显式锁定,但仅在该方法的持续时间上。方法完成后,将返回锁,其他线程可以自由使用它。
答案 1 :(得分:2)