设计模式:单例模式

来源:互联网 发布:mac访客模式 编辑:程序博客网 时间:2024/06/04 19:57

简单来说,单例模式指在应用的整个生命周期中,只存在一个实例对象。由此可知,单例模式可用于那些整个应用中只存在一个对象的场景,如配置文件、线程池、缓存、例子对象、工具类等。如果创造出多个对象,会出现很多问题,如占用过多资源、不一致的结果等。

UML类图

根据是否lazy初始化,可将单例模式分为“饿汉”和“懒汉”式实现。

“饿汉”式实现

“饿汉”式实现 会在整个应用启动初始化时,就会创建一个实例对象。“饿汉”式实现 是线程安全的,但是由于在应用启动时创建,所以会使得应用启动时间变长。

常规实现

public class Singleton {    // 静态变量,声明并初始化    private static Singleton instance = new Singleton();    // 私有化构造方法    private Singleton() {    }    // 对外提供示例获取的静态方法    public static Singleton getInstance() {        return instance;    }}

实现简单,线程安全。

枚举实现

public enum Singleton {    INSTANCE;    public void method_name() {    }    ...}

这种方式是绝对线程安全的,并支持自动序列化机制。

“懒汉”式实现

“懒汉”式实现 在应用启动时不会立即创建一个实例对象,是在首次被请求调用获取实例对象的方法时才创建对应的实例对象,所以应用启动过程相对“饿汉”式实现会快一点。

简单实现

public class Singleton {    // 静态变量,仅声明    private static Singleton instance;    // 私有化构造方法    private Singleton() {    }    // 对外提供示例获取的静态方法    public static Singleton getInstance() {        if(instance == null) {            instance = new Singleton();        }        return instance;    }}

多线程环境下,非线程安全。

常规实现

public class Singleton {    // 静态变量,仅声明    private static Singleton instance;    // 私有化构造方法    private Singleton() {    }    // 对外提供示例获取的静态方法,使用Synchronized加锁    public static Synchronized Singleton getInstance() {        if(instance == null) {            instance = new Singleton();        }        return instance;    }}

多线程情况下,线程安全,但加锁 synchronized影响效率。

双重锁实现

双检锁/双重校验锁(DCL,即 double-checked locking),实现示例如下:

public class Singleton {    // 静态变量,仅声明;volatile保证及时可见性    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;    }}

线程安全;双重锁校验,可保证多线程下的高性能。

静态内部类实现

public class Singleton {    private static class SingletonHolder {        private static final Singleton INSTANCE = new Singleton();    }    // 私有化构造方法    private Singleton() {    }    public static Singleton getInstance() {        return SingletonHolder.INSTANCE;    }}

线程安全;这种实现使用了classloader机制,达到的效果和双重锁实现差不多。

总结

一般情况下,不建议使用 简单实现 和 常规实现 方式,建议使用“饿汉”式实现。只有在要明确实现 lazy loading 效果时,使用静态内部类的方式更佳。如果涉及到反序列化创建对象时,可以尝试使用枚举实现方式。如果有其他特殊的需求,可以考虑使用双重锁校验方式。