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

时间:2016-09-05 14:15:51

标签: java multithreading java-memory-model

以下代码

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行为的原因以及为什么在这种情况下同步方法的行为与同步(此)块的行为不同?

提前谢谢。

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

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

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