出现多例的原因
- 线程不安全, 多线程同时创建
- 单例由不同的类装载器装入,那便有可能存在多个单例类的实例
- 类现了java.io.Serializable接口,就可能被序列化和反序列化。
反序列化一个单例类的对象,就会有多个单例类的实例
1.懒汉(线程不安全)
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
2.懒汉
线程安全, 效率很低
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3.饿汉
利用了classloder的机制来保证初始化instance时只有一个线程
Singleton类被装载instance就会被实例化 ,所以线程是安全的.
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
4.饿汉变种
同3
public class Singleton {
private Singleton instance = null;
static {
instance = new Singleton();
}
private Singleton (){}
public static Singleton getInstance() {
return this.instance;
}
}
5.静态内部类
- 与3 4的区别是 可以lazy loading懒加载
调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
6.枚举
不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
7.双重校验锁
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}