【问题标题】:Is there any case where I should prefer 'volatile' over exclusive synchronization?在任何情况下我应该更喜欢“易失性”而不是排他同步?
【发布时间】:2012-06-30 14:01:32
【问题描述】:

我知道在 Java 中使用 volatile 关键字我们会得到某种弱同步(它允许可见性更新但不提供实际锁定)。在实现并发程序时,是否有任何情况下 volatile 应优先于实际锁定。 SO上有一个类似的问题,上面写着volatile as a synchronization mechanism,但它被标记为C#。

【问题讨论】:

  • This answer 解释了为什么 volatile 并不总是足够好。这同样适用于 Java 和 C#。

标签: java multithreading synchronization


【解决方案1】:

如果共享状态包含在单个字段中,并且您不使用任何 get-and-set 构造(例如i++)来分配它,那么 volatile 就足够了。不过,大多数 volatile 用法都可以用 AtomicXxx 类型代替(它提供原子的 get-and-set 操作)。

【讨论】:

    【解决方案2】:

    简而言之,您应该更愿意在不需要的地方避免使用锁,因为锁会使您的程序陷入死锁,并通过从代码的关键部分排除并发性来降低性能。所以,只要情况允许,一定要依靠volatile;如果您还需要像比较和交换这样的原子两步操作,请使用AtomicReference。回退到synchronized 仅适用于这是唯一选项的情况。例如,如果您需要延迟初始化重对象,则需要锁来防止双重初始化——但同样,不要获取已经初始化的实例 (double-check idiom)。

    【讨论】:

    • OTOH,volatile 是一个不太容易理解的关键字,在许多情况下,同步不会导致任何显着的性能开销。大多数时候,使用高级 API(阻塞队列、原子、信号量、并发集合等)是最好和最安全的技术。
    • 也就是说,许多高级 API 在内部使用 volatile
    • ... 并从根本上建立在volatile 保证之上。许多 ajava.util.concurrent 类的 Javadoc 明确指定其语义“就像写/读 volatile”。
    • @JBNizet 我要补充一点,遗憾的是没有很好理解,因为它是一个非常简单的概念。我认为这只是因为 Java 1.5 的语义还没有流行起来(现在已经有将近十年了)。
    • @seh 感谢您的 em-dash,我需要开始使用它...(也是 en-dash)。
    【解决方案3】:

    Volatile 保证所有线程都会看到任何其他线程对变量的最后一次写入,仅此而已。不涉及同步。如果您同步实例变量的读取和写入方法,那么您不必使该变量易失(所有线程都会看到最近的写入)。

    【讨论】:

      猜你喜欢
      • 2013-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-30
      • 1970-01-01
      • 2011-04-01
      • 1970-01-01
      相关资源
      最近更新 更多