我有一个静态变量的类,像这样
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
,或者为该字段的每次访问添加相同的同步。