【问题标题】:synchronize without volatile无 volatile 同步
【发布时间】:2018-10-13 15:43:39
【问题描述】:

我了解 synchronize 和 volatile 的作用以及它们的使用位置。我刚刚学习了 volatile,我对什么时候可以在没有 volatile 的情况下使用同步感到困惑。如果我同步一个对象,我需要阻止其他线程使用相同的对象,但在大多数情况下,我会这样做来编辑对象,如果是这样,我需要在我正在编辑的属性上设置 volatile 。

以下代码是关于竞争条件的,我想知道为什么我从未见过有人在 count 变量上使用 volatile:

  public synchronized void add(int value){
      this.count += value;
  }

这里不应该算 volatile 吗?

我只是想找出一个可以在没有 volatile 的情况下使用 synchronize 的情况,一段代码会有所帮助。

【问题讨论】:

    标签: java multithreading synchronization volatile


    【解决方案1】:

    很明显volatile 不足以实现计数器,因为它不能保证原子性。但是,如果读取次数大大超过修改次数,您可以结合使用内在锁定和 volatile 变量来降低公共代码路径的成本。看看这个,

    public class Counter {
        @GuardedBy("this") private volatile int value;
    
        public int getValue() { return value; }
    
        public synchronized int increment() {
            return value++;
        }
    }
    

    代码使用 synchronized 来保证自增操作是原子的,使用 volatile 来保证当前结果的可见性。如果更新不频繁,则此方法可能会执行得更好,因为读取路径上的开销仅为volatile 读取,这通常比获取锁更便宜。

    【讨论】:

    • 同步应该还不够吧?我想知道为什么没有人在他们的例子中使用它。我可以有没有 volatile 单独同步的例子吗?我似乎找不到,因为每个编辑都应该可见。
    • 如果您 synchronize 它,则不再需要 volatile。但这会很慢,因为它涉及大量的锁定获取。
    • synchronized 为您提供与volatile 相同的可见性。所以不需要。
    • @PeterLawrey 感谢您提供这些文件,但我有一个疑问,即使该数据是由非同步块操作的,同步是否始终确保读取一致的数据? synchronized method A(){ this.count // 如果另一个线程在 B() 方法中修改它,它是否总是读取最新的更改? } 方法 B(){ this.conunt++; ....}
    猜你喜欢
    • 2017-03-13
    • 2011-08-22
    • 2014-05-16
    • 2018-05-31
    • 1970-01-01
    • 2011-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多