Java 中的同步块与同步方法限定符

Synchronized block vs. synchronized method qualifier in Java

下面的代码

public class Coordination {

    private  volatile int counter =  0;

    public static void main(String ... args) throws Exception {
        new Coordination().volatileWithCoordination();
    }

    public synchronized void inc() {
        counter++;
    }

    public void volatileWithCoordination() throws Exception {

        Thread th1 = new Thread(new Runnable() {

            @Override
            public void run() {
                for(int k = 0; k < 10_000_000; k++) {
                    synchronized(this) {
                        //inc();
                        counter++;
                    }
                }
            }});

        Thread th2 = new Thread(new Runnable() {

            @Override
            public void run() {
                for(int k = 0; k < 10_000_000; k++) {
                    //synchronized(this) {
                    inc();
                    //counter++;
                    //}
                }

            }});

        th1.start();
        th2.start();

        th1.join();
        th2.join();
        System.out.println("counter: "+counter);
    }
}

显示 counter: 18025867 的不正确和不确定的结果,而切换到:

            inc();
        //counter++;

在第一个线程 (th1) 的 Runnable 中给出了预期的输出:

counter: 20000000

是什么导致了这种 lost update 行为?为什么在这种情况下同步方法的行为与同步(this)块不同?

提前致谢。

两个线程都需要在同一个对象上获取监视器,以下更改(在两个线程中的一个或两个线程上)修复了这种情况:

synchronized(Coordination.this) {
                    inc();
                //counter++;
                }

您的线程正在不同的对象上同步。您的 th2 线程调用同步 inc() 方法,该方法在 Coordination class 的实例上同步;但是当你的 th1 线程执行 synchronized(this) 时,this 关键字引用匿名内部 Runnable class 的实例,而不是 Coordination class.