Java 在简单的单例实例化中获取ExceptionInInitializerError
我一定在做一些很愚蠢的事情,但是当我尝试在我的Singleton中实例化一个对象时,我得到了一个ExceptionInInitializerError:Java 在简单的单例实例化中获取ExceptionInInitializerError,java,exception,static,singleton,initializer,Java,Exception,Static,Singleton,Initializer,我一定在做一些很愚蠢的事情,但是当我尝试在我的Singleton中实例化一个对象时,我得到了一个ExceptionInInitializerError: class MySingleton { private static MySingleton instance = null; private OtherObject obj; // Do I instantiate obj here??? private MySingleton() { //obj = new Ot
class MySingleton {
private static MySingleton instance = null;
private OtherObject obj;
// Do I instantiate obj here???
private MySingleton() {
//obj = new OtherObject();
}
// Or here?
{
//obj = new OtherObject();
}
// Or where? ...
public static MySingleton getInstance() {
if (instance == null)
instance = new MySingleton();
return instance;
}
}
我应该在构造函数中创建另一个对象,还是对于单例来说它总是应该为空?我在构造函数和初始值设定项块中都得到了异常
这是主要的()
您应该在构造函数中实例化OtherObj。给出错误的确切代码是什么 编辑——以下内容对我有用
class MySingleton {
private static MySingleton instance = null;
private Integer obj;
private MySingleton() {
obj = new Integer(2);
}
public static MySingleton getInstance() {
if (instance == null)
instance = new MySingleton();
return instance;
}
}
然后我从主循环调用getInstance。你可能想看看
您应该在构造函数中实例化OtherObj。给出错误的确切代码是什么 编辑——以下内容对我有用
class MySingleton {
private static MySingleton instance = null;
private Integer obj;
private MySingleton() {
obj = new Integer(2);
}
public static MySingleton getInstance() {
if (instance == null)
instance = new MySingleton();
return instance;
}
}
然后我从主循环调用getInstance。你可能想看看
静态初始化部分用于初始化标记为Static的类的成员。因为OtherObject obj不是静态的,所以不应该在那里初始化它。正确的位置是在构造函数中初始化它
如果在构造函数中有
obj=new OtherObject()
时出现异常InInitializeError,则问题可能是另一个类(可能是OtherObject?)错误地初始化了静态成员。静态初始化部分用于初始化标记为static的类的成员。因为OtherObject obj不是静态的,所以不应该在那里初始化它。正确的位置是在构造函数中初始化它
如果在构造函数中有
obj=new OtherObject()
时遇到异常InInitializerError,则问题可能是另一个类(可能是OtherObject?)错误地初始化了静态成员。您可以通过消除风险来避免一些混淆(您目前在例外情况中为此付费)。既然您实际上只是返回静态实例,为什么不在运行时创建该静态实例(即不要等待null):
如果您注意到了,现在一切都是确定的和直接的。您的MySingleton.instance在运行时填充,并通过静态方法MySingleton.getInstance()
访问
我意识到这与原始GOF设计模式书中的确切模式不匹配,但您会注意到该类的用法实际上是相同的
编辑:继其他答案和评论中提出的一些线程安全点之后,我将尝试说明问题和GOF书中最初提出的解决方案是如何非线程安全的。要获得更好的参考,请参阅我在ACM/Safari在线书架上拥有的。坦白地说,这是一个更好的解决方案比我略图中的例子更有趣,但是,嘿,我们只能努力
因此,假设我们有两个名为Thread1和Thread2的线程,并且,巧合的是,每个线程都会命中MySingleton.getInstance()方法。这在现代多核超线程系统中是完全可能的。现在,即使这两个线程碰巧同时到达此方法的入口点,也无法保证哪一个线程会到达任何特定语句。因此,您可以看到如下情况:
// Note that instance == null as we've never called the lazy getInstance() before.
Thread1: if (instance == null)
Thread2: if (instance == null) // both tests pass - DANGER
Thread1: instance = new MySingleton();
Thread2: instance = new MySingleton(); // Note - you just called the constructor twice
Thread1: return instance; // Two singletons were actually created
Thread2: return instance; // Any side-effects in the constructor were called twice
Thread1: return instance;
Thread2: return instance;
if null测试中说明的问题称为a。您无法知道谁将在何时执行哪条语句。因此,这就像两条线程正在向悬崖赛跑
如果您查看我的示例的同一种检查,两个线程仍在同一时刻命中getInstance(),您会看到如下内容:
// Note that instance == null as we've never called the lazy getInstance() before.
Thread1: if (instance == null)
Thread2: if (instance == null) // both tests pass - DANGER
Thread1: instance = new MySingleton();
Thread2: instance = new MySingleton(); // Note - you just called the constructor twice
Thread1: return instance; // Two singletons were actually created
Thread2: return instance; // Any side-effects in the constructor were called twice
Thread1: return instance;
Thread2: return instance;
简单化了,是的,但这是我的观点。对象在很久以前构造过一次,线程可以指望它的值是一致的。不存在竞争
注意:您仍然需要担心OtherObject的构造函数的内容。这里的教训是:并发性很难。如果您要使构造函数线程安全(这是您应该做的),请确保OtherObject的作者也对您表示同样的礼貌。您可以通过消除风险来避免一些混淆(您目前在例外情况中为此付费)。既然您实际上只是返回静态实例,为什么不在运行时创建该静态实例(即不要等待null): 如果您注意到了,现在一切都是确定的和直接的。您的MySingleton.instance在运行时填充,并通过静态方法
MySingleton.getInstance()
访问
我意识到这与原始GOF设计模式书中的确切模式不匹配,但您会注意到该类的用法实际上是相同的
编辑:继其他答案和评论中提出的一些线程安全点之后,我将尝试说明问题和GOF书中最初提出的解决方案是如何非线程安全的。要获得更好的参考,请参阅我在ACM/Safari在线书架上拥有的。坦白地说,这是一个更好的解决方案比我略图中的例子更有趣,但是,嘿,我们只能努力
因此,假设我们有两个名为Thread1和Thread2的线程,并且,巧合的是,每个线程都会命中MySingleton.getInstance()方法。这在现代多核超线程系统中是完全可能的。现在,即使这两个线程碰巧同时到达此方法的入口点,也无法保证哪一个线程会到达任何特定语句。因此,您可以看到如下情况:
// Note that instance == null as we've never called the lazy getInstance() before.
Thread1: if (instance == null)
Thread2: if (instance == null) // both tests pass - DANGER
Thread1: instance = new MySingleton();
Thread2: instance = new MySingleton(); // Note - you just called the constructor twice
Thread1: return instance; // Two singletons were actually created
Thread2: return instance; // Any side-effects in the constructor were called twice
Thread1: return instance;
Thread2: return instance;
if null测试中说明的问题称为a。您无法知道谁将在何时执行哪条语句。因此,这就像两条线程正在向悬崖赛跑
如果您查看我的示例的同一种检查,两个线程仍在同一时刻命中getInstance(),您会看到如下内容:
// Note that instance == null as we've never called the lazy getInstance() before.
Thread1: if (instance == null)
Thread2: if (instance == null) // both tests pass - DANGER
Thread1: instance = new MySingleton();
Thread2: instance = new MySingleton(); // Note - you just called the constructor twice
Thread1: return instance; // Two singletons were actually created
Thread2: return instance; // Any side-effects in the constructor were called twice
Thread1: return instance;
Thread2: return instance;
简单化了,是的,但这是我的观点。