【问题标题】:Is volatile on getter and synchronized on setter the same as synchronized on both?getter 上的 volatile 和 setter 上的同步是否与两者上的同步相同?
【发布时间】:2015-04-04 11:04:52
【问题描述】:

在并发程序中,这样安全吗:


private volatile int i;

public int getI() {
    return i;
}

public synchronized incrementI() {
    i++;
}

?

根据我对synchronize 的了解,这些更改保证在i 上仅适用于在同一对象上获取锁监视器的线程。 所以我认为,上面的代码是不安全的。如果属实,请确认,否则,请解释。 谢谢。

【问题讨论】:

    标签: java concurrency synchronized volatile


    【解决方案1】:

    此代码是线程安全的。同步方法中的更改会传递给所有线程。 而且由于您已将其设置为 volatile,因此所有线程都不会缓存它,因此会获取最新的副本。

    这个帖子也会有帮助Java volatile modifier and synchronized blocks

    【讨论】:

    • 不幸的是,这个答案是不正确的。 “同步方法中的更改不会传递给所有线程”,也不是“如果你让它变得易失,所有线程都不会缓存它”。这是一个正确的答案:stackoverflow.com/a/29446437/2613885
    • @AlekseyShipilev 如果您不使变量易失,那么各个线程会将其值缓存在堆栈中。还更新同步块中的变量,并在存储它的所有线程中更新其值。你同意吗?你所说的最终会导致这种情况。那怎么回答错了。
    • 不,我不同意“更新同步块中的变量并在所有存储它的线程中更新其值”,这 不是 Java 内存模型提供的.我不同意使变量 volatile “只是”将其暴露给内存的前提,从那一刻起一切都很好。这是一种危险的想法,内存排序比这复杂得多。
    • 请仔细阅读我链接的示例:shipilev.net/blog/2014/jmm-pragmatics/…。如果您有任何不明白的地方,请阅读帖子的其余部分。
    【解决方案2】:

    “JMM 语用学”here 中几乎给出了确切的示例。

    volatile 提供了happens-before 边以使setter 之前的更改对getter 之后发生的所有事情都可见,假设getter 实际观察到了设置值。 synchronized in setter 另外给出了互斥,volatile 不能单独保证。

    【讨论】:

    • “假设 getter 实际观察到设定值”是什么意思。这是否意味着 OP 中提供的代码不安全?注:我是并发新手,我认为在深入挖掘之前需要熟悉一些基本概念。无论如何,感谢您提供详细信息。我必须研究它。
    • “volatile 提供了发生前的边缘以使 setter 之前的更改对 getter 之后发生的所有事情都可见”是什么意思?您是否假设 setter -> getter 的特定执行顺序? “在setter之前改变”是什么意思?
    • 回答这两个问题:“假设吸气剂实际观察到设定值”是这里的关键。 IF getter 观察到 setter 设置的值,那么 setter 之前的所有动作都发生在 getter 之后的任何动作之前。这里没有假设“执行顺序”,JMM 只说 if volatile read 观察到 volatile write 设置的值,happens-before(通过 synchronizes-with)诞生。
    【解决方案3】:

    由于整数 i 是类的私有实例变量,同步实例方法将起作用。您需要确保添加到修改 i 的类的所有方法都必须使用相同的对象监视器进行同步。

    请注意 i++ 不是自动表达式,因此只有 volatile 不起作用。

    您可以将 AtomicInteger 用于像这样的单个值。

    【讨论】:

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