【问题标题】:Understanding JVM guarantees for immutable objects理解 JVM 对不可变对象的保证
【发布时间】:2016-10-28 07:33:05
【问题描述】:

Java并发实战有如下例子:

@ThreadSafe
public class VolatileCachedFactorizer implements Servlet {
    private volatile OneValueCache cache = new OneValueCache(null, null);

    public void service(ServletRequest req, ServletResponse resp) {
        BigInteger i = extractFromRequest(req);
        BigInteger[] factors = cache.getFactors(i);
        if (factors == null) {
            factors = factor(i);
            cache = new OneValueCache(i, factors);
        }
            encodeIntoResponse(resp, factors);
        }
    }
}

OneValueCache 是不可变的。

据我了解,使用 volatile 可确保所有线程都能看到存储在 cache 变量中的最新引用。

同时它说

任何线程都可以安全地使用不可变对象,而无需额外的 同步,即使不使用同步来发布它们。

对我来说,它表明我们实际上不需要上面用于同步的volatile。

JLS也有如下例子:

class FinalFieldExample {
    final int x;
    int y; 

    static FinalFieldExample f;

    public FinalFieldExample() {
        x = 3;
        y = 4;
    }

    static void writer() {
        f = new FinalFieldExample();
    }

    static void reader() {
        if (f != null) {
            int i = f.x; // guaranteed to see 3
            int j = f.y; // could see 0
        }
    }
}

他们不使用volatile 字段f。不是说其他​​线程可以看到f为null,而永远看不到创建的实例吗?

谁能解释一下?

【问题讨论】:

  • 对象不可变,变量不可变。
  • 你把两个非常不同的东西混为一谈: - 一个对象,如果被指定为不可变的,那么它是线程安全的。 - 一个变量(指一个对象)可以指向任何其他对象,因此需要volatile 关键字来确保使用该变量的任何组件都可以访问该变量所指的任何内容的最新副本
  • 让我感到困惑的是Immutable objects can be published through any mechanism. 分配给变量是一种机制,但这样做不是线程安全的,对吧?
  • 因为我们使用 volatile 我们也可以在第一个示例中使用有效的可变类。 volatile 保证构造不会被重新排序并分配给 volatile。阅读线程也会看到它。

标签: java concurrency java-memory-model


【解决方案1】:

据我了解,使用 volatile 可确保所有线程都能看到缓存变量中存储的最新引用。

没错,但是这个概念适用于变量而引用自JCiP的语句

任何线程都可以安全地使用不可变对象,而无需额外的 同步,即使不使用同步来发布它们。

不适用于变量,但适用于对象本身。这意味着线程将始终看到一个完全构造的对象,而不会发生任何数据竞争,而与它的发布方式无关,因为正如 JCiP 所述

不可变对象可以通过任何机制发布。

现在关于你的第二个例子:

不是说其他​​线程可以看到f为null,而永远看不到创建的实例吗?

没错。如果一个线程调用writer(),其他线程可能会将f 视为null 或f.y 视为0,因为它不尊重安全发布:

3.5.3。安全出版习语

为了安全地发布对象,对对象的引用和 对象的状态必须同时对其他线程可见。 正确构造的对象可以通过以下方式安全发布:

  • 从静态初始化器初始化对象引用;
  • 将对其的引用存储到 volatile 字段或 AtomicReference 中;
  • 将对它的引用存储到正确构造的 > 对象的最终字段中;或
  • 将对它的引用存储到由锁适当保护的字段中。

【讨论】:

  • can be published through any mechanism。分配给cache 变量不是发布机制吗?
  • 是的。你指的是我does not apply to a variable but to the object itself的说法吗?这是关于Immutable objects can be used safely。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-16
  • 2012-11-09
  • 2021-11-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多