线程安全 在 Java 中实现单例模式的有效方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4482533/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Thread Safe Efficient way to implement singleton pattern in Java?
提问by Pradeep
Possible Duplicate:
Efficient way to implement singleton pattern in Java
可能的重复:
在 Java 中实现单例模式的有效方法
I was reading this Best Singleton Implementation In Java, but its not thread safe.
我正在阅读这个Java 中的最佳单例实现,但它不是线程安全的。
As per wiki :
根据维基:
if(singleton==null) { synchronized(Singleton.class) { // this is needed if two threads are waiting at the monitor at the // time when singleton was getting instantiated if(singleton==null) singleton= new Singleton(); }
}
if(singleton==null) { synchronized(Singleton.class) { // this is needed if two threads are waiting at the monitor at the // time when singleton was getting instantiated if(singleton==null) singleton= new Singleton(); }
}
But Find Bugs utility gives two errors in this : 1. Double null check. 2. Incorrect lazy initialization of static field.
但是 Find Bugs 实用程序在这方面给出了两个错误: 1. 双空检查。2. 静态字段的延迟初始化不正确。
What is the best way,
什么是最好的方法,
Is it Correct :
这是正确的吗 :
synchronized (Singleton.class) { if (singleton== null) { singleton= new Singleton(); } }
synchronized (Singleton.class) { if (singleton== null) { singleton= new Singleton(); } }
采纳答案by Peter Lawrey
The most efficient/simplest way to make a lazy loading Singleton is just
制作延迟加载单例的最有效/最简单的方法就是
enum Singleton {
INSTANCE
}
Note: there is no need for locking as class loading is thread safe. The class is final by default and the constructor cannot be called via reflection. The INSTANCE will not be created until the INSTANCE, or the class is used. If you are worried the class might be accidentally used you can wrap the singleton in an inner class.
注意:不需要锁定,因为类加载是线程安全的。该类默认为 final,不能通过反射调用构造函数。在 INSTANCE 或类被使用之前不会创建 INSTANCE。如果您担心该类可能会被意外使用,您可以将单例包装在一个内部类中。
final class Singleton {
private Singleton() { }
static class SingletonHolder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
IMHO, you have to be pretty paranoid to consider this a better solution.
恕我直言,你必须非常偏执才能认为这是一个更好的解决方案。
回答by Eli Acherkan
The first code sample in the accepted answer for Efficient way to implement singleton pattern in Javaisthread safe. The creation of the INSTANCE
is performed by the class loader the first time the class is loaded; it's performed exactly once, and in a thread-safe way:
在 Java 中实现单例模式的有效方法的公认答案中的第一个代码示例是线程安全的。的创建INSTANCE
由类加载器在第一次加载类时执行;它只执行一次,并且以线程安全的方式执行:
public final class Foo {
private static final Foo INSTANCE = new Foo();
private Foo() {
if (INSTANCE != null) {
throw new IllegalStateException("Already instantiated");
}
}
public static Foo getInstance() {
return INSTANCE;
}
}
(copied from What is an efficient way to implement a singleton pattern in Java?)
The 2nd code sample in the question is correct and thread-safe, but it causes synchronization on each call to getInstance()
, which affects performance.
问题中的第二个代码示例是正确的并且是线程安全的,但它会导致每次调用同步getInstance()
,从而影响性能。
回答by Eyal Schneider
A lot has been written about this issue. Yes, the simple double-check-locking pattern is not safe. But you can make it safe by declaring the static instance as volatile. The new Java Memory Model specification adds some code-reordering restrictions for compilers when dealing with volatile, therefore the original risks are gone.
关于这个问题已经写了很多。是的,简单的双重检查锁定模式并不安全。但是您可以通过将静态实例声明为 volatile 来使其安全。新的 Java 内存模型规范在处理 volatile 时为编译器增加了一些代码重新排序的限制,因此原始风险消失了。
Anyway, I rarely really need this kind of lazyness when creating the instance, so I usually simply create it statically at class-loading time:
无论如何,我在创建实例时很少真正需要这种惰性,所以我通常只是在类加载时静态创建它:
private static MyClass instance = new MyClass();
This is short and clear. As an alternative, if you really want to make it lazy, you can take advantage of the class loading characteristics and do this:
这是简短而明确的。作为替代方案,如果您真的想让它变得懒惰,您可以利用类加载特性并执行以下操作:
public class MyClass {
private static class MyClassInit {
public static final MyClass instance = new MyClass();
}
public static MyClass getInstance() {
return MyClassInit.instance;
}
...
}
The nested class will not be loaded until the first time you call getInstance().
直到第一次调用 getInstance() 时才会加载嵌套类。