【问题标题】:when use synchronized to lock write, if need volatile to guard to avoid the read old value or not full value?当使用同步锁定写入时,是否需要 volatile 来保护以避免读取旧值或不完整值?
【发布时间】:2012-06-06 05:26:31
【问题描述】:

如标题。我已经使用同步来保护多线程写入。但我想知道是否需要添加 volatile 来保护读取。 (正如我们所知,我也可以使用同步来保护读取,但它会阻止读取和写入一致。更重要的是,如果我使用可重入锁。它也会阻止。)

private volatile BigDecimal cacheMiss = BigDecimal.ZERO;

public  BigDecimal getCacheHit() {
    return cacheHit;
}

public void increaseCacheMiss() {
    synchronized (cacheMissLock) {
        this.cacheMiss = this.cacheMiss.add(STEP);
    }
}

【问题讨论】:

  • 如果您不希望跟踪超过 20 亿次缓存命中,您可以使用 Java 5 的 AtomicLong 而无需自己进行任何同步。

标签: java multithreading volatile synchronized


【解决方案1】:

如果cacheMiss 可以从多个线程更新,那么如果您绝对需要读取最新值,则需要将其声明为volatile。否则,线程可能正在读取线程本地值(隐藏在寄存器或核心缓存中),而不是去主内存查看最新值。

【讨论】:

  • 谢谢。但我想知道为什么我需要添加 volatile。一些书籍提到:同步也可以保护可见性。那么为什么我仍然需要 volatile 来保护可见性?
  • @jiafu - 如果你所有的访问都在synchronized 块中,那么你不需要声明它volatile。但是在您的示例代码中,您的读取位于 synchronzed 块之外。有一篇很棒的文章 here 探讨了这个问题。
  • 我明白你的意思。谢谢 。但我还有一个问题。如果 synchronized 可以防止代码在保护代码内部重新编码。我在这个网站上查询了这个问题。有人说它不能阻止同步代码的保护代码内部的重新编码。更重要的是,一些书籍提到: volatile 可以禁用重新排序。那么你有什么看法呢?
  • 根据一些书籍和我的理解。我认为同步只会防止同步代码块和其他同步代码之间的重新编码。但是 volatile 可以防止代码围绕其他代码重新编码。我说的对吗?
  • @jiafu - volatile 确实可以防止重新排序。在synchronized 块中,重新排序不是问题,因为(通过适当的同步)只有持有锁的线程可以访问变量。 (重新排序曾经是编写线程安全单例的问题——参见here——但大部分问题在 Java 5 中已修复,没有使用volatile。)
猜你喜欢
  • 2012-05-26
  • 2021-01-30
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 2021-06-13
  • 1970-01-01
  • 1970-01-01
  • 2021-11-02
相关资源
最近更新 更多