设计模式—单例模式

1.定义

确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

2.使用场景

例如:在一个应用中,应该只有一个ImageLoader实例,这个ImageLoader中既包含线程池、缓存系统、网路请求等,创建这个实例非常消耗系统资源,因此没有理由让它多次构建。这种不能自由构造对象的情况就是单例模式的使用场景。其他的例如:IO操作、数据库操作等。

3.关键点

1)将构造函数私有化(privat关键字),不对外开放

2)通过一个静态方法对外提供单利类对象

3)确保单例对象有且只有一个,尤其是在多线程的环境下

4)确保单利类对象在反序列化时不会重新去构建对象

4.实现

方式一:懒汉模式

/**
 * 单例模式-懒汉模式
 */
public class SingleTon {

    private static SingleTon INSTANCE;

    private SingleTon() {

    }

    private static synchronized SingleTon getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new SingleTon();
        }
        return INSTANCE;
    }

}

优点:确保该实例只有在使用时才会被实例化,在一定程度上节约了系统资源,同时使用关键字synchronized保证了全局对象的唯一性。

缺点:第一次加载时需要及时进行实例化,反应稍慢,以后每次调用时都需要进行同步,造成不必要的同步开销。

方式二:Double Check Lock

/**
 * 单例模式-Double Check Lock
 */
public class SingleTon {

    private static SingleTon INSTANCE;

    private SingleTon() {

    }

    private static SingleTon getInstance() {
        if (INSTANCE == null) {
            synchronized (SingleTon.class) {
                if (INSTANCE == null) {
                    INSTANCE = new SingleTon();
                }
            }
        }
        return INSTANCE;
    }

}

注:两次判空的意义:1是为了避除处第一次创建需要同步之外其他不必要的同步2是为了在null的情况下创建实例,保证全局实例的唯一性

优点:资源利用率高,第一次执行getInstance时单例对象才会被实例化,效率高。

缺点:第一次加载时,反应稍慢,由于Java的内存模型原因偶尔会失败,在高并发情况下也有一定缺陷

方式三:静态内部类单例模式

/**
 * 单例模式-静态内部类单例模式
 */
public class SingleTon {

    private SingleTon() {

    }

    private static SingleTon getInstance() {
        return SingleTonHolder.INSTANCE;
    }

    public static class SingleTonHolder {
        private static final SingleTon INSTANCE = new SingleTon(); 
    }

}

注:当第一次加载SingleTon类的时候并不会实例化INSTANCE,只有第一次调用SingleTon的getInstance方法时才会导致INSTANCE实例化。因此,第一次调用getInstance方法会导致虚拟机加载SingleTonHolder类。

优点:即能够确保线程安全,又能够保证单例对象的唯一性,同时延迟了单例的实例化,所以这是推荐的单例模式实现方式。

方式四:容器注入方式

/**
 * 单例模式-容器注入方式
 */
public class SingleTonManager {

    private static Map<String,Object> singleTonMap = new HashMap<String,Object>();

    private SingleTonManager(){}

    public static void registerSingleTon(String key,Object instance){
        if(!singleTonMap.containsKey(key)){
            singleTonMap.put(key,instance);
        }
    }

    public static Object getSingleTon(String key){
        return singleTonMap.get(key);
    }

}

注:在程序开始的时候,将多种单例类型注入到一个统一的管理类当中,在使用的时候根据key获取对象对应类型的对象。

优点:管理多种类型单例对象,需要时通过统一的接口进行获取操作,降低了用户使用成本,也对用户隐藏了具体的实现细节,降低了耦合度。

核心思想

单例模式的核心思想是将构造函数私有化,并且通过静态方法获取一个唯一的实例,在这个获取的过程中必须保证线程安全、防止反序列化重新生产实例对象等问题。

小结

单例模式时运用频率很高的设计模式,但是由于在客户端通常没有高并发的情况,因此,选择哪种实现方式并不会有太大的影响,即便如此,出于效率考虑,我们仍推荐使用Double Check Lock和静态内部类的方式实现。

优点:

1.由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁创建的时候,而且创建或销毁时性能又无法优化,因此使用单例模式就会有很大的优势

2.由于单例模式只生成了一个实例,所以减少了系统的性能开销,当一个对象的产生需要花费较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后用永久驻留内存的方式实现。

3.单例模式剋避免对资源的多重占用,例如一个写文件操作,由于只有一个实例存在在内存中,避免对同一个文件的同时写操作。

4.单例模式可以在系统设置全局的访问点,优化和共享资源访问。

缺点:

1.单例模式一般没有接口,扩展很困难,若要扩展,只有修改代码一种方式。

2.单例对象如果持有Context,很容易引起内存泄漏,此时需要注意传递给单例对象的Context最好是同单例对象生命周期同步的,例如ApplicatonContext。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值