参考链接:https://www.runoob.com/design-pattern/singleton-pattern.html
一、单例模式
单例模式属于创建型模式。一个单一的类,创建自己的对象,同时确保只有单个对象被创建。给外部提供了一种访问其唯一的对象的方法,不再需要实例化该类的对象。
二、单例模式的常见实现形式
1.懒汉式,线程不安全
- 延迟加载,减少内存占用;
- 线程不安全,没有加锁 synchronized,不能在多线程使用
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
2.懒汉式,线程安全
- 延迟加载,减少内存占用
- 线程安全,但是执行效率低,大部分情况下不需要锁
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3.饿汉式,线程安全
- 类加载就初始化,浪费内存。可能被类中其它静态变量方法的调用引起类的初始化
- 没有加锁,执行效率搞。利用classloader的机制,避免了线程同步的问题
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
4.双检锁
- 延迟加载,减少内存占用
- 双重加锁的机制在多线程使用场景下保持性能
- 不加volatile锁定属性的话,可能由于内存重排,导致b在c后面发生,线程不安全
a:分配内存空间
b:初始化对象
c:将对象指向刚分配的内存空间
public class Singleton {
private volatile static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
5.静态内部类
- 能达到和双检锁一样的功效(延迟加载+性能保证),实现更简单,在第三方库里边比较常见。
- 也是利用classloader机制实现线程安全。但是在类其它静态方法被调用时,SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
6.枚举
- 未延迟加载,线程安全,实现单例模式的最佳方法。它更简洁,还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
三、总结
不建议使用懒汉式,建议使用饿汉方式。只有在要明确实现 lazy loading 效果时,才会使用静态内部类。如果涉及到反序列化创建对象时,可以尝试使用枚举方式。如果有其他特殊的需求,可以考虑使用双检锁方式。
延迟加载:静态内部类>双检索
非延迟加载:枚举>饿汉式
网友评论