【问题标题】:Should I volatile the field with synchronized methods?我应该使用同步方法来改变字段吗?
【发布时间】:2018-07-16 03:12:29
【问题描述】:

以下课程,

// 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 字段吗?

【问题讨论】:

    标签: java multithreading synchronized volatile


    【解决方案1】:

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

    volatile 可以保证读者线程总是获得新鲜的balance 值,但它不能使balance += amount; 原子化。 synchronized 两者都可以。

    【讨论】:

    • getter 必须是 synchronized 还是无关紧要(即它无论如何都会返回更新值,因为更新在同步块中)?
    • @JaroslawPawlak 如果字段不是volatile,则必须。
    【解决方案2】:

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

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

    如果你去掉 synchronized 关键字并留下变量 volatile,你就会遇到问题,因为虽然 volatile 确保更新可见,但并不能确保更新是原子的。这里的+=-= 操作不是原子的,可能会受到并发运行的线程的干扰。

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

    【讨论】:

      猜你喜欢
      • 2012-12-16
      • 2011-03-26
      • 1970-01-01
      • 1970-01-01
      • 2017-01-14
      • 1970-01-01
      • 1970-01-01
      • 2020-03-17
      相关资源
      最近更新 更多