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、饿汉式
多线程安全
当类加载的时候,就创建对象。好处是没有线程安全的问题,坏处是浪费内存空间。
public class Singleton {
private static Singleton instance = new Singleton();
//私有构造方法
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
4、双检锁/双重校验锁
多线程安全
综合了懒汉式和饿汉式两者的优缺点。在synchronized关键字内外都加了一层 if 条件判断,这样既保证了线程安全,又比直接上锁提高了执行效率,还节省了内存空间。
public class Singleton {
private volatile static Singleton instance;
//私有构造方法
private Singleton (){}
public static Singleton getInstance() {
if (instance== null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
5、登记式/静态内部类
多线程安全
静态内部类的方式效果类似双检锁,实现更简单,但这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
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 anyMethod() {
}
}
总结
一般情况下,懒汉式(线程安全和线程不安全方式)都比较少用,不建议使用;
建议使用饿汉式方式;
在要明确实现 lazy loading 效果时,可以考虑静态内部类的实现方式;
如果涉及到反序列化创建对象时,可以尝试使用枚举方式;
如果有其他特殊的需求,可以考虑使用双检锁方式;