在以下课程中,
// 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
吗?
答案 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类可以做得更好。