【问题标题】:What happens if a volatile variable is written from 2 threads?如果从 2 个线程写入 volatile 变量会发生什么?
【发布时间】:2016-12-12 03:07:54
【问题描述】:

考虑 Java 并发实践中的 sn-p-

@ThreadSafe
public class SynchronizedInteger{
    @GuardedBy("this") private int value;

    public synchronized int getValue() {
        return value;
    }

    public synchronized void setValue(int value) {
        this.value = value;
    }
}

同一本书的摘录-

考虑 volatile 变量的一个好方法是想象它们 行为大致类似于上面清单中的 SynchronizedInteger 类, 用 get 调用替换 volatile 变量的读取和写入 并设置。然而访问 volatile 变量不会执行锁定,因此 不能导致执行线程阻塞,使变量易变 一种比 synchronized 更轻量级的同步机制。

线程限制的一种特殊情况适用于 volatile 变量。只要确保 volatile 变量仅从单个线程写入,对共享 volatile 变量执行读-修改-写操作是安全的。

所以,如果你把上面类中的实例变量设置为 volatile,然后去掉 synchronized 关键字,之后假设有 3 个线程

线程 A 和线程 B 正在写入同一个 volatile 变量。
线程 C 读取 volatile 变量。

既然 volatile 变量现在是从 2 个线程写入的,为什么对这个共享的 volatile 变量执行 read-modify-write 操作是不安全的?

【问题讨论】:

    标签: java multithreading volatile


    【解决方案1】:

    关键字volatile 用于确保对您的Object 所做的更改将被其他Threads 看到。 这并不强制,Object 上的非原子操作将在操作完成之前在没有其他 Thread 干扰的情况下执行。 要执行此操作,您将需要关键字synchronized

    【讨论】:

      【解决方案2】:

      这是因为对 volatile 变量的读-修改-写操作不是原子的。 v++ 实际上是这样的:

      r1 = v;
      r2 = r1 + 1;
      v = r2;
      

      因此,如果您有两个线程分别执行一次此操作,则可能导致变量仅增加一次,因为它们都读取旧值。这就是为什么它不安全的一个例子。

      在您的示例中,如果您删除同步,使字段易失并且有两个线程在基于 getValue 的返回的一些条件逻辑之后调用 setValue,这将是不安全的 - 该值可能已被另一个线程修改。

      如果您想要原子操作,请查看 java.util.concurrent.atomic 包。

      【讨论】:

        【解决方案3】:

        如果你在不使用任何同步结构的情况下从多个线程写入 volatile 变量,则必然会出现数据不一致错误。

        在单个写入线程和多个读取线程进行原子操作的情况下,使用不同步的 volatile 变量。

        Volatile 确保变量值是从主内存而不是线程缓存中获取的。在单写多读操作的情况下使用是安全的。

        使用原子变量或同步或 Lock API 从多个线程更新和读取变量。

        参考相关的 SE 问题:

        What is meant by "thread-safe" code?

        【讨论】:

          【解决方案4】:

          如果两个线程在没有先读取变量的情况下进行写入,没有问题..它是安全的。如果线程首先读取,然后修改然后写入,就会出现问题。如果第二个线程也在同时读取,读取与第一个线程相同的旧值,然后修改它。当它写入时,它会简单地覆盖第一个线程更新。轰隆隆。

          val i = 1 -> 线程读取 1 -> 线程 2 读取 1 -> 线程 1 执行 1 * .2 = 1.2 -> 线程 2 执行 1 * .3 = 1.3 -> 线程 1 将 1.2 写回 -> 线程 2cooly 将其覆盖为 1.3做 1.2 * .3

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-07-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-02-11
            • 1970-01-01
            相关资源
            最近更新 更多