Java下实现线程安全的单例模式有如下4种方式:(直接上代码)
public class Singleton {
static class SingletonA {
private static final SingletonA INSTANCE = new SingletonA();
public static SingletonA getInstance() {
return INSTANCE;
}
private SingletonA() {
System.out.println("SingletonA ctor");
}
public void printName() {
System.out.println("This is " + getClass().getSimpleName());
}
}
static class SingletonB {
private static class InstanceHolder {
private static final SingletonB INSTANCE = new SingletonB();
}
public static SingletonB getInstance() {
return InstanceHolder.INSTANCE;
}
private SingletonB() {
System.out.println("SingletonB ctor");
}
public void printName() {
System.out.println("This is " + getClass().getSimpleName());
}
}
static class SingletonC {
private volatile static SingletonC INSTANCE;
public static SingletonC getInstance() {
if (INSTANCE == null) {
synchronized (SingletonC.class) {
if (INSTANCE == null) {
INSTANCE = new SingletonC();
}
}
}
return INSTANCE;
}
private SingletonC() {
System.out.println("SingletonC ctor");
}
public void printName() {
System.out.println("This is " + getClass().getSimpleName());
}
}
enum SingletonD {
INSTANCE;
private SingletonD() {
System.out.println("SingletonD ctor");
}
public void printName() {
System.out.println("This is " + getClass().getSimpleName());
}
}
public static void main(String[] argv) {
SingletonA.getInstance().printName();
SingletonB.getInstance().printName();
SingletonC.getInstance().printName();
SingletonD.INSTANCE.printName();
SingletonA.getInstance().printName();
SingletonB.getInstance().printName();
SingletonC.getInstance().printName();
SingletonD.INSTANCE.printName();
}
}
Java中Class的静态代码块是在Class被第一次使用,ClassLoader加载时执行的,只执行一次(如果被多个ClassLoader加载,则会执行多次),并且是线程安全的; Enum的任何一个枚举值都是在第一次使用时构造的,并且构造过程是线程安全的。上面4种方法的优缺点如下:
方式 | 优点 | 缺点 |
---|---|---|
A | 简洁 | Class第一次被访问时,单例就被构造了,而不是延迟到getInstance() 被调用时才构造 |
B | 简洁,单例延迟到getInstance() 被调用时才构造 |
暂无 |
C | 单例延迟到getInstance() 被调用时才构造 |
相对复杂 |
D | 简洁,单例延迟到getInstance() 被调用时才构造 |
Java 1.5才引入这个特性,另外Enum不能像Class一样被继承 |
参考阅读
Java Spec by Oracle
Implementing Singleton with an Enum (in Java)
Are Java static initializers thread safe?
Singleton class design