【问题标题】:How stale data is avoided using synchronized keyword?如何使用 synchronized 关键字避免过时的数据?
【发布时间】:2019-10-02 17:46:30
【问题描述】:

在《Java Concurrency in Practice》一书中,3.1.1 状态数据一节下,有一段代码

@NotThreadSafe
public class MutableInteger {
private int value;
public int  get() { return value; }
public void set(int value) { this.value = value; }
}

这不是线程安全的,因为:

如果一个线程调用set,其他线程调用get可能会也可能不会看到 那个更新。

而在 set 和 get 方法上使用同步关键字使其“正确”。怎么样?

@ThreadSafe
public class SynchronizedInteger {
@GuardedBy("this") private int value;
public synchronized int get() { return value; }
public synchronized void set(int value) { this.value = value; }
}

如果 value 为 0,并且线程 A 调用了 set(2),而线程 B 调用了 get(),B 可能会得到值 0,然后 A 会将其设置为 2...之前的代码已经这样做了.那么我们从同步代码中得到了什么好处..

可能是我遗漏了什么,但请指导。谢谢

【问题讨论】:

标签: java multithreading


【解决方案1】:

您以这种方式解决的问题不是线程 B 在 A 执行 get 之后立即执行集合,而是仍然会返回“旧”(嗯,当时在技术上是正确的,但是很快就会出错)价值。

同步修复的问题是,即使线程 B 线程 A 读取之前写入,由于缓存(很可能是 CPU 缓存,但这取决于 JVM 实现)。从非易失性变量的非同步读取可以使用缓存值。换句话说:同步创建了一个读屏障,这意味着“你必须重新读取这个值,即使你的 CPU 缓存中已经有了它”。

请注意,对于这种特定情况,只需将 volatile 添加到 value 即可产生相同的效果,但对于更复杂的访问模式 synchronized(或在较新的 API 中等效 Lock)是必要的。

【讨论】:

  • 谢谢约阿希姆。明白了
【解决方案2】:

当您使用同步方法时,您可以获得对处于“竞争条件”风险中的对象的独占访问权限。在这种情况下,您可以获得对该值的独占访问权。 之所以达到这个目的,是因为同步方法使用了信号量。

Synchronized in Java Java Doc - 在这里你可以找到一个很好的例子。

来自 Java 文档: 如果 count 是 SynchronizedCounter 的一个实例,那么使这些方法同步有两个效果:

首先,

在同步方法上的两次调用是不可能的 交错的同一个对象。

当一个线程为一个对象执行同步方法时,所有 为同一对象调用同步方法的其他线程 阻塞(暂停执行),直到第一个线程完成 对象。

其次,当一个同步方法退出时,它会自动与任何后续对同一对象的同步方法调用建立起之前的关系。这保证了对象状态的更改对所有线程都是可见的。

【讨论】:

    【解决方案3】:

    这一切都与官方 Java 文档所称的“发生在关系之前”有关。

    在您的两个同步的 getter 和 setter 方法分别读取和写入同一个实例变量的情况下,这取决于操作的顺序,即首先调用的是 getter 还是 setter。

    这种关系只是保证一个特定语句的内存写入对另一个特定语句可见。

    两个动作可以通过happens-before关系排序。如果一个动作发生在另一个动作之前,那么第一个动作对第二个动作可见并在第二个动作之前排序。

    同步是实现这种一致性的方法之一。在您的特定情况下,另一种方法是将变量设为 volatile。

    来自official Java docs

    使用 volatile 变量可降低内存一致性的风险 错误,因为对 volatile 变量的任何写入都会建立 与后续读取相同的发生之前的关系 多变的。这意味着对 volatile 变量的更改总是 对其他线程可见。

    【讨论】:

      猜你喜欢
      • 2019-02-27
      • 2013-01-27
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多