常规方式
- 懒汉式 DCL「双重检测锁:Double Checked Lock」
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
// 延迟初始化
instance = new Singleton();
}
}
}
return instance;
}
}
优点:线程安全;延迟加载;效率较高。
缺点:由于volatile关键字会屏蔽Java虚拟机所做的一些代码优化,略微的性能降低。
- 饿汉式(静态常量)
public class Singleton {
private final static Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
缺点:使用静态final的实例对象或者使用静态代码块依旧不能解决在反序列化、反射、克隆时重新生成实例对象的问题(见参考1)
枚举方式
- 饿汉式枚举单例
public enum T {
SPRING,SUMMER,AUTUMN,WINTER;
}
// 反编译之后可知枚举中的各个枚举项是通过static来定义的
public final class T extends Enum
{
//省略部分内容
public static final T SPRING;
public static final T SUMMER;
public static final T AUTUMN;
public static final T WINTER;
private static final T ENUM$VALUES[];
static
{
SPRING = new T("SPRING", 0);
SUMMER = new T("SUMMER", 1);
AUTUMN = new T("AUTUMN", 2);
WINTER = new T("WINTER", 3);
ENUM$VALUES = (new T[] {
SPRING, SUMMER, AUTUMN, WINTER
});
}
}
- 懒汉式枚举单例(枚举+内部类)
enum LanguageEnum {
INSTANCE;
private static class Language {
public String realName(String name) {
return "Language " + name;
}
}
private Language instance = null;
private LanguageEnum() {
instance = new Language();
}
// 实际对外开放的两个方法
public Language getLanguage() {
return instance;
}
public void printlnLanguageName(String name) {
String str = getLanguage().realName(name);
System.out.println(str);
}
}
使用枚举的好处:
- 定义的代码少,主要是系统帮忙做了文中反编译那部分。
- 线程安全