为什么同步计数本身不起作用?

Why does synchronized on the count itself do not work?

为什么同步计数不安全?

class Increment implements Runnable{
    static Integer count = new Integer(0);

    public void run(){
        for (int i = 0; i< 1_000_000; i++){
            synchronized (count){
                count ++;
            }

        }
    }

    public static void main(String[] args) throws InterruptedException {

        Thread one = new Thread(new Increment());
        Thread two = new Thread(new Increment());

        one.start();
        two.start();
        one.join();
        two.join();

        System.out.print(count);

    }
}

1555622

我知道我是否会像这样放一些虚拟对象 o

class Increment implements Runnable{
    static Integer count = new Integer(0);

    static Object o = new Object();
    public void run(){
        for (int i = 0; i< 1_000_000; i++){
            synchronized (o){
                count ++;
            }
        }    }

    public static void main(String[] args) throws InterruptedException {

        Thread one = new Thread(new Increment());
        Thread two = new Thread(new Increment());

        one.start();
        two.start();
        one.join();
        two.join();

        System.out.print(count);

    }
}

2000000

会很安全。但我不明白为什么它对计数本身不起作用

因为锁不在变量上,而是在对象上。 Integer 是不可变的,当你增加它时你会得到一个新对象,它会替换你锁定的对象。每次线程尝试进入同步块时,它都会计算括号中的表达式以找到它应该锁定的内容。

这会造成一个线程锁定旧对象而传入线程锁定新对象的情况,您可以在同步块中有两个线程。

您的固定解决方案有效,因为所有线程都共享同一个锁并且它不会改变。