我应该使用同步方法来改变字段吗?

时间:2018-07-16 03:12:29

标签: java multithreading synchronized volatile

在以下课程中,

// This class should be thread-safe!!!
class BankAccount {

    private long balance; // Should it be volatile?

    synchronized void deposit(long amount) {
        // ...
        balance += amount;
    }

    synchronized void withdraw(long amount) {
        // ...
        balance -= amount;
    }
}

我应该在volatile字段中添加balance吗?

2 个答案:

答案 0 :(得分:4)

否,与synchronized关键字相比,volatile是轻量级的。

volatile可以保证读取器线程始终获得新的balance值,但不能使balance += amount;成为原子。 synchronized可以做到。

答案 1 :(得分:3)

在所示的代码中您不需要volatile,因为该变量仅在synchronized方法中使用。 synchronized方法确保变量的内容可见且不陈旧,并且确保每个synchronized方法内执行的操作均不受并发运行线程的干扰。 volatile关键字在这里是多余的,它只能确保变量的内容可见。

如果您希望变量的值对未在该对象上输入synchronized实例方法的线程可见(也许您希望将其用于未获得锁定的方法中实例),那么在这种情况下保留volatile就有意义。

如果您删除了synchronized关键字并留下了变量volatile,则会遇到问题,因为尽管volatile确保可以看到更新,但不能确保更新是原子的。此处的+=-=操作不是原子操作,并且会受到并发运行的线程的干扰。

或者考虑使用AtomicLong代替,在此示例中,您可能不需要synchronized关键字(取决于// ...中的代码的作用)。像addAndGet这样的方法会对原子存储的值进行更改。对于大多数以前使用过volatile的事情,Atomic类可以做得更好。