在简单单例实例化中获取 ExceptionInInitializerError
我一定做了一些非常愚蠢的事情,但是当我尝试在单例中实例化一个对象时,我收到了 ExceptionInInitializerError :
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;
}
}
我应该在构造函数中创建另一个对象,还是对于单例来说它总是应该为空?我在构造函数和初始化块中都遇到异常...
这是 main():
public static void main(String[] args) {
try {
MySingleton singleton = MySingleton.getInstance();
} catch (Error e) {
System.err.println("Error!");
}
}
I must be doing something very silly, but I'm getting a ExceptionInInitializerError when I try to instantiate an object in my Singleton:
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;
}
}
Should I make the other object in the constructor, or is that always supposed to be empty for singletons? I get the exception in both the constructor and the initializer block...
Here's the main():
public static void main(String[] args) {
try {
MySingleton singleton = MySingleton.getInstance();
} catch (Error e) {
System.err.println("Error!");
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
静态初始化部分用于初始化标记为静态的类的成员。由于 OtherObject obj 不是静态的,因此不应在那里初始化。正确的地方是在构造函数中初始化它。
如果在构造函数中有 obj = new OtherObject() 时出现 ExceptionInInitializerError,则问题可能出在另一个类(也许是 OtherObject?) 上,该类未正确初始化静态成员。
Static initialization sections are for initializing members of the class marked static. Since OtherObject obj isn't static it should not be initialized there. The correct place is to initialize it in the constructor.
If you are getting an ExceptionInInitializerError when you have
obj = new OtherObject()
in the constructor, the problem may be with another class (OtherObject perhaps?) that is incorrectly initializing static members.您应该在构造函数中实例化 OtherObj 。给出错误的确切代码是什么?
编辑 - 以下内容对我有用
,然后我只需从主循环中调用 getInstance 。您可能想查看
http://en.wikipedia.org/wiki/Singleton_pattern#Java
you should instantiate OtherObj in your constructor. What is the exact code that is giving the error?
edit -- The following worked for me
and then I just call getInstance from a main loop. You might want to look at
http://en.wikipedia.org/wiki/Singleton_pattern#Java
答案很简单,不要使用单例。虽然 GoF 书中有一些好的想法,但单例模式并不是其中之一。
正如其他人在上游所说,单例的正确线程安全使用很棘手,请参阅
IBM 关于线程安全单例的文章
实际上,单例实现的所有内容都是全局对象。这很糟糕,它污染了名称空间。它使得正确的单元测试(Junit 等)变得更加困难,甚至不可能。你永远不需要它。简单的静态工厂类是更干净的代码,避免了全局污染并且代码更少。
The answer is simple, don't use Singletons. While the GoF book has some good ideas, the singleton pattern is not one of them.
As others have said upthread, the proper thread safe use of singletons is tricky, see
IBM article on thread safe singletons
In reality, all a Singleton implements is a global object. This is bad, it pollutes the namespace. It makes proper unit testing (Junit, etc) much harder if not impossible. You don't need it, ever. A simple static factory class is cleaner code, avoids the global pollution and is less code.
你的 Singleton 类在这里没有问题。我猜想 OtherObject 类的构造函数有问题。
正确的语法是:
现在,您只需向我们提供有关 OtherObject 的更多信息:-)
Your Singleton class is not at fault here. I would guess a problem in the contructor of the OtherObject class.
A correct syntax would be:
Now, you just need to give us more information about the OtherObject :-)
您可以通过消除延迟初始化风险(您目前正在为此付费)来避免一些混乱在例外情况下)。既然您实际上只是返回静态实例,为什么不在运行时创建该静态实例(即,不要等待 null):
如果您注意到,现在一切都是确定性且简单的。您的 MySingleton.instance 在运行时填充,并通过静态方法
MySingleton.getInstance()
访问。我意识到这与原始 GOF 设计模式书中的确切模式不匹配,但您会注意到该类的用法实际上是相同的。
编辑:跟进其他答案和评论中提出的一些线程安全点,我将尝试说明问题和 GOF 书中最初提出的解决方案如何是非线程的安全的。要获得更好的参考,请参阅我拥有并放在 ACM / Safari 在线书架上的 Java Concurrency in Practice。坦率地说,它是比我草拟的示例更好的来源,但是,嘿,我们可以努力......
所以,想象我们有两个名为 Thread1 和 Thread2 的线程,巧合的是,每个线程同时命中 MySingleton.getInstance() 方法。这在现代多核超线程系统中是完全可能的。现在,即使这两个线程碰巧同时命中该方法的入口点,也无法保证哪一个线程会命中任何特定语句。因此,您可能会看到类似这样的内容:
if-null 测试中说明的问题称为 竞争条件。你无法知道谁会在什么时候发表什么声明。结果,就好像两条线程都在互相竞争,冲向悬崖。
如果您查看我的示例的相同类型的检查,其中两个线程仍然同时命中 getInstance(),您会看到类似这样的内容:
简单化,是的,但这就是我的观点。该对象很久以前就被构造过一次,并且线程可以依赖它的值是一致的。不存在种族。
注意:您仍然需要担心 OtherObject 构造函数的内容。教训是:并发很难。如果您要使构造函数线程安全(您应该这么做),请确保 OtherObject 的作者也以同样的方式为您提供帮助。
You can avoid some of your confusion by eliminating the lazy initialization risk (which you're currently paying for in the exception). Since you're really just returning your static instance, why not just create that static instance at run time (i.e., don't wait for null):
If you notice, now everything is deterministic and straightforward. Your MySingleton.instance is populated at runtime and is accessed via the static method
MySingleton.getInstance()
.I realize that this doesn't match the exact pattern of the original GOF design patterns book but you'll notice that the usage of the class is effectively the same.
EDIT: following up on some of the thread safety points raised in other answers and comments, I'm going to try to illustrate how the original proposed solution in the question and in the GOF book is non-thread safe. For a better reference, see Java Concurrency in Practice which I own and have on my ACM / Safari online bookshelf. It is frankly a better source than my sketched example but, hey, we can but strive....
So, imagine we have two threads named Thread1 and Thread2 and, coincidentally, each hits the MySingleton.getInstance() method at the same moment. This is entirely possible in a modern multicore hyperthreaded system. Now, even though these two threads happened to hit the entry point of this method at the same time, there's no assurance of which is going to hit any particular statement. So, you could see something like this:
The problem illustrated in the if-null test is called a race condition. You can't know who's going to what statement when. As a result, it's like both threads are racing each other to a cliff.
If you look at the same sort of examination of my example with both threads still hitting getInstance() at the same moment, you see something like this:
Simplistic, yes, but that's my point. The object was constructed once, long ago, and the threads can count on its value being consistent. No race exists.
NOTE: you still have to worry about the contents of the constructor for OtherObject. The lesson there is: concurrency is hard. If you're making your constructor thread safe (which you should), make sure that the author of OtherObject is doing you the same courtesy.