小编典典

不变性可以确保线程安全吗?

java

好吧,考虑Immutable下面给出的不可变类:

public final class Immutable
{
    final int x;
    final int y;
    public Immutable(int x,int y)
    {
        this.x = x;
        this.y = y;
    }
    //Setters
    public int getX()
    {
        return this.x;
    }
    public int getY()
    {
        return this.y;
    }
}

现在,我正在Immutable一个类中创建一个对象,Sharable该对象的对象将由多个线程共享:

public class Sharable
{
    private static Immutable obj;
    public static Immutable getImmutableObject()
    {
        if (obj == null) --->(1)
        {
            synchronized(this)
            {
                if(obj == null)
                {
                    obj = new Immutable(20,30); ---> (2)
                }
            }
        }
        return obj; ---> (3)
    }
}

Thread A看到objas null并移入同步块并创建对象。现在,由于
Java内存模型(JMM)允许多个线程在初始化开始之后但尚未结束之前观察对象。 因此,Thread B可以将写入操作obj视为在写入的字段之前发生Immutable。因此,因此Thread B可以看到部分构造Immutable,该构造很可能处于无效状态,并且其状态以后可能会意外更改。

它不是Immutable非线程安全的吗?


编辑
好,在仔细研究了SO并进行了一些评论之后,我知道 您可以 在构造对象之后 安全地在线程之间共享对不可变对象的引用
。另外,如@Makoto所述, 通常需要声明包含其引用的字段为volatile,以确保可见性
。另外,如@PeterLawrey所述,将对不可变对象的引用声明为,final使字段为thread-safe


阅读 297

收藏
2020-11-30

共1个答案

小编典典

因此,线程B可以看到对objas的写入发生在对Immutable字段的写入之前。因此,线程B可能因此看到部分构造的不可变,该不可变很可能处于无效状态,并且其状态以后可能会意外更改。

在Java 1.4中,这是正确的。在Java 5.0及更高版本中,构造后的final字段是线程安全的。

2020-11-30