Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 访问相同同步方法的不同线程返回意外结果_Java_Multithreading_Synchronized - Fatal编程技术网

Java 访问相同同步方法的不同线程返回意外结果

Java 访问相同同步方法的不同线程返回意外结果,java,multithreading,synchronized,Java,Multithreading,Synchronized,我很难理解synchronized是如何在同一对象的两个不同方法上工作的。 我有一个类,有两个声明为synchronized的实例方法。 三个线程访问此对象的两个同步方法,但结果出乎意料。线程可以互换地访问这两种方法。它们不会等待整个对象的锁被释放。 以下是示例: public class ThreadSafeCounterSameMonitor2 { private int value; public synchronized int getValue() {

我很难理解synchronized是如何在同一对象的两个不同方法上工作的。 我有一个类,有两个声明为synchronized的实例方法。 三个线程访问此对象的两个同步方法,但结果出乎意料。线程可以互换地访问这两种方法。它们不会等待整个对象的锁被释放。 以下是示例:

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