设计模式之单例模式

2023-02-12  本文已影响0人  Tinyspot

1. 单例模式(Singleton)

2. 实战

public static void main(String[] args) throws Exception {
    for (int i = 0; i < 10; i++) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Singleton.getInstance().hashCode());
            }
        }).start();
    }
}

2.1 饿汉式

public class Singleton {
    // final 常量, 私有构造方法
    private static final Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}

2.2 懒汉式

public class Singleton {
    private static Singleton instance = null;

    private Singleton() {}
    
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

改进:双重校验锁

public class Singleton {
    private static Singleton instance = null;
    
    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

2.3 静态内部类写法(也是懒汉式)

public class Singleton {
    private static Singleton instance = null;

    private static class Holder {
        static Singleton singleton = new Singleton();
    }

    public static Singleton getInstance() {
        return Holder.singleton;
    }
}

优点:外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化instance,不占内存
只有当 getInstance() 第一次被调用时,才会去初始化INSTANCE,第一次调用getInstance()方法会导致虚拟机加载SingleTonHoler类,这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。

2.4 容器式单例

容器式单例写法适用于需要大量创建单例对象的场景,便于管理,但它是非线程安全的

public class ContainerSingleton {

    private static Map<String, Object> beanMap = new ConcurrentHashMap<>();

    private ContainerSingleton() {

    }

    public static Object getBean(String className) {
        synchronized (beanMap) {
            if (beanMap.containsKey(className)) {
                return beanMap.get(className);
            } else {
                Object obj = null;
                try {
                    obj = Class.forName(className).newInstance();
                    beanMap.put(className, obj);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return obj;
            }
        }
    }
}

扩展:Spring中的容器式单例
Spring中的 Bean 默认是单例模式的,框架并没有对bean进行多线程的封装处理,Bean 是全局共享的,所以不是线程安全的
若需要线程安全的 Bean, 改变 Bean 的作用域 把 "singleton" 改为 "protopyte"

上一篇 下一篇

猜你喜欢

热点阅读