Java 访问相同同步方法的不同线程返回意外结果
我很难理解synchronized是如何在同一对象的两个不同方法上工作的。 我有一个类,有两个声明为synchronized的实例方法。 三个线程访问此对象的两个同步方法,但结果出乎意料。线程可以互换地访问这两种方法。它们不会等待整个对象的锁被释放。 以下是示例:Java 访问相同同步方法的不同线程返回意外结果,java,multithreading,synchronized,Java,Multithreading,Synchronized,我很难理解synchronized是如何在同一对象的两个不同方法上工作的。 我有一个类,有两个声明为synchronized的实例方法。 三个线程访问此对象的两个同步方法,但结果出乎意料。线程可以互换地访问这两种方法。它们不会等待整个对象的锁被释放。 以下是示例: public class ThreadSafeCounterSameMonitor2 { private int value; public synchronized int getValue() {
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()方法中,我设置了一个值,然后检索它,它给了我另一个值,从另一个线程更改而来
我经常读到类似“同步方法获取此引用上的隐式锁”之类的内容,但这显然不是真的,即使对于同一个监视器中的所有同步方法也不是这样。还是我在代码中做了什么坏事
我的问题是,如何才能真正锁定整个对象的同步方法?你知道一个很好地解释这个概念的教程吗?这里没有不可预测的结果。同步工作正常。问题是您调用方法
setValue()
,然后在一段时间后调用getValue()
。在您的示例中,线程以这样的方式覆盖,即在其他线程调用setValue()
之后设置值15,但在它们调用getValue()
之前设置值15
您可以在第三个线程的run()
方法中添加Thread.sleep(1000)
,并查看结果可能会发生变化
同步方法获取对象上的显式锁,但仅限于该方法的持续时间。方法完成后,将返回锁,其他线程可以自由使用它。您已经创建了3个线程并启动了它,因此,我希望您知道,线程的执行不能立即得到保证。您创建并启动的线程可能会在最后开始运行,这在您的情况下是可能的。但是,这并不总是保证。例如,我已经执行了相同的代码,它在 但是,若您想一个接一个地执行线程,那个么您可以查看该方法
Thread Id 8, expected value is 5, value=5
Thread Id 9, expected value is 10, value=10
Thread Id 10, expected value is 15, value=15