是通过引用访问一个延迟初始化的非易失性String线程安全吗?

问题描述 投票:0回答:2

我有一个String字段,初始化为null但后来可能被多个线程访问。在首次访问时,该值将被懒惰地初始化为幂等计算值。

这个字段是否必须是volatile才能是线程安全的?

这是一个例子。

public class Foo {
    private final String source;
    private String BAR = null;

    public Foo(String source) {
        this.source = source;
    }

    private final String getBar() {
        String bar = this.BAR;
        if (bar == null) {
            bar = calculateHashDigest(source); // e.g. an sha256 hash
            this.BAR = bar;
        }
        return bar;
    }

    public static void main(String[] args) {
        Foo foo = new Foo("Hello World!");
        new Thread(() -> System.out.println(foo.getBar())).start();
        new Thread(() -> System.out.println(foo.getBar())).start();
    }
}

我使用System.out.println()作为示例,但我并不担心当它的调用是互锁时会发生什么。 (虽然我很确定这也是线程安全的。)

BAR需要是volatile吗?

我认为答案是否定的,volatile不是必需的,是的,它是线程安全的,主要是因为这个excerpt from JLS 17.5

final字段还允许程序员在没有同步的情况下实现线程安全的不可变对象。线程安全的不可变对象被所有线程视为不可变的,即使使用数据争用传递线程之间的不可变对象的引用也是如此。

而且因为char value[]String领域确实是final

int hash不是final,但它的懒惰初始化看起来也很合适。)

编辑:编辑以阐明用于BAR的值是固定值。它的计算是幂等的,没有副作用。我不介意是否跨线程重复计算,或者由于内存缓存/可见性,BAR实际上变为线程本地。我担心的是,如果它是非空的,那么它的值是完整的而不是某种程度上是偏的。

java concurrency thread-safety atomicity
2个回答
© www.soinside.com 2019 - 2024. All rights reserved.