java – Synchronized()块未按预期工作

private static Integer balance=0;

public static void deposit(final int amt) {
    Thread t = new Thread(new Runnable() {
        public void run() {
            synchronized(balance) {
                System.out.println("Balance at start is: "+balance);        
                balance+=amt;
                System.out.println("deposited " + Integer.toString(amt) + " to funds. Now at " + Integer.toString(balance));
            }
        }
    });
}

当我运行上面的简单存款函数时,我希望两个线程不应该在synchronized块中同时进入.但是操作顺序如下:

> Depo100
> Depo200
> Depo700

输出如下:

------------------
Balance at start is: 0
deposited 100 to funds. Now at 100
Balance at start is: 100
Balance at start is: 100
deposited 700 to funds. Now at 800
deposited 200 to funds. Now at 1000

我们可以看到在同步块中同时输入两个线程并访问了不期望的平衡对象.
        我在这做错了什么?我是多线程的新手.
        提前致谢.

最佳答案
整数(与所有原始包装类一样)是不可变的.每次“向其添加数字”时,您实际上都是将字段设置为新实例:

balance += amt;

实际上评估如下:

balance = Integer.valueOf(balance.intValue() + amt);

所以你每次都在同步不同的对象(除非碰巧是零,而balance.intValue()是in the range cached by your JVM’s implementation of Integer.valueOf).

您需要一个可以同步的固定值.您可以使用具有可变值的固定引用,例如长度为1的Integer []或AtomicInteger(尽管AtomicInteger上的同步对我来说总觉得有点不对 – 但实际上,您不需要使用同步,因为你可以使用AtomicInteger.getAndIncrement或AtomicInteger.incrementAndGet).

请注意,您可能应该引用最终同步的事物,以避免意外地将其设置为某个不同的值并再次打破互斥.

有关详细信息,请参见this question.

转载注明原文:java – Synchronized()块未按预期工作 - 代码日志