构造函数中的同步块



我有一个静态变量的类,像这样

private static Object sMyStaticVar;

如果我想在构造函数中给这个变量赋值,我有这样的代码

if(sMyStaticVar == null) sMyStaticVar = new CustomObject(someRuntimeObject);

,其中someRuntimeObject是一个在我的类加载时不可用的对象,因此阻止我像下面这样声明静态变量

private static Object sMyStaticVar = new CustomObject(someRuntimeObject);

我的问题是,静态var对象的初始化在构造函数线程安全吗?我的直觉告诉我它不是,我应该使用非运行时类类型作为锁进行同步,就像下面的

synchronized(MyClass.class)
{
    if(sMyStaticVar == null) sMyStaticVar = new CustomObject(someRuntimeObject);
}

(相对于从getClass()获得的runTime类型)

但由于我的直觉通常是错误的,如果有人能给我一些启示,我会很感激!

如果它是静态的,你不应该在构造函数中赋值它。创建一个静态初始化方法来完成public static synchronized void initialize(someRuntimeObject)

注意synchronized关键字:它与在MyClass.class上同步是一样的

你是对的,以下是开放的竞争条件:

if(sMyStaticVar == null) sMyStaticVar = new CustomObject(someRuntimeObject);

两个线程可以同时检查sMyStaticVar,参见null,创建两个对象,等等…

这意味着您需要同步。您可以在某个现有对象上同步(有多种选择),或者您可以仅为这个目的创建一个对象,这样您就不必与其他人共享锁,从而冒不必要的争用风险:

private static Object sMyStaticVar;
private static Object sMyStaticVarLock = new Object();
然后,在构造函数中:
synchronized(sMyStaticVarLock)
{
    if(sMyStaticVar == null) sMyStaticVar = new CustomObject(someRuntimeObject);
}

这种同步是必需的,但它不足以实现线程安全。

您还需要确保在访问字段值时它的可见性。因此,您应该将该字段声明为volatile,或者为该字段的每次访问添加相同的同步。

最新更新