好的,考虑下面给出的不可变类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;
}
}
现在我正在一个类Sharable
中创建一个Immutable
对象,这个对象将被多个线程共享:
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
看到obj
为null
,进入同步块并创建对象。由于Java内存模型(JMM)允许多个线程在初始化开始之后但尚未结束之前观察对象。因此,Thread B
可以看到对obj
的写操作发生在对Immutable
字段的写操作之前。因此,Thread B
可能会看到一个部分构建的Immutable
,它可能处于无效状态,并且其状态可能会意外更改。
这难道不是使Immutable
不安全吗?
编辑
好的,在Stack Overflow上进行了很多查找并阅读了一些评论后,我知道了在对象构造完成后,您可以安全地在线程之间共享对不可变对象的引用。 此外,正如@Makoto所提到的,通常需要将包含其引用的字段声明为易失性,以确保可见性。 此外,正如@PeterLawrey所述,将对不可变对象的引用声明为final
会使该字段成为线程安全
。
public class Sharable { public static final Immutable obj = new Immutable(); }
,这样更简单且线程安全。 - Peter Lawrey