23种设计模式之单例模式

定义:确保一个类中只有一个实例,而且自行实例化并向整个系统提供这个实例。或者说某种类型的对象有且只有一个。
实现单例模式主要有以下几个关键点:

  • 构造函数不对外开放,一般为Private
  • 通过一个静态方法或者枚举返回单例类对象
  • 确保单例类的对象有且只有一个,尤其是在多线程环境下
  • 确保单例类对象在反序列化时不会被重新构建对象。

单例的实现方式有多重:饿汉式,懒汉式,静态内部类,双重校验锁(DCL),枚举等,推荐使用静态内部类和双重校验锁。
1.饿汉式:

/**
 * Created by jmfstart on 2017/5/5.
 * 饿汉式
 */

public class Singleton {
    private static final Singleton singleton = new Singleton();
    private Singleton() {

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

这种方式基于类加载机制避免了多线程的同步问题,不过,instance在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getInstance方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance显然没有达到懒加载的效果。
2.懒汉式(线程不安全的)

/**
 * Created by jmfstart on 2017/5/5.
 * 懒汉式
 */

public class Singleton {
    private static  Singleton singleton ;
    private Singleton() {

    }
    public static Singleton getInstance() {
        if(singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

这种写法懒加载很明显,但是致命的是在多线程不安全。
3.懒汉式(线程安全的)

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){

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

大家细想,假如对象已经被初始化instance,现在每次调用getInstance()方法时都会进行同步,这会消耗不必要的资源。不建议使用
4.Double Check Lock(DCL)实现单例

/**
 * Created by jmfstart on 2017/5/5.
 * DCL方式实现
 */

public class Singleton {
    private static  Singleton singleton ;
    private Singleton() {

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

优点:资源利用率高。
缺点:第一次加载时反应稍慢。在高并发环境下也有一定的缺陷,虽然发生的概率很小。
DCL模式是使用最多的单例实现方式,它能够在需要时才实例化单例对象。这种方式一般能够满足需求。
5.静态内部类单例模式
DCL在某些情况下出现失效的问题,这个问题被称为双重检验锁(DCL)失效,建议使用静态内部类替代

/**
 * Created by jmfstart on 2017/5/5.
 * 静态内部类实现单例
 */

public class Singleton {
    private Singleton() {

    }
    public static Singleton getInstance() {
        return SingletonHolder.singleton;
    }
    //静态内部类
    private static class SingletonHolder {
        private static  Singleton singleton = new Singleton(); 
    }
}

这种方式不仅能够保证线程安全,也能够保证单例对象的唯一性,同时也延迟了单例的实例化,所以这是推荐使用的单例模式的实现方式。
6.枚举类实现单例

/**
 * Created by jmfstart on 2017/5/5.
 * 枚举实现单例
 */
public enum Singleton {
    INSTANCE;
    public void doSomething() {
        System.out.println("do sth.");
    }
}

这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,不过,个人认为由于1.5中才加入enum特性,用这种方式写不免让人感觉生疏,在实际工作中,我也很少看见有人这么写过。
7.使用容器实现单例模式
这种实现方式比较另类

/**
 * Created by jmfstart on 2017/5/5.
 * 单例的集合,便于管理
 */

public class SingletonManager {
    private static Map<String,Object> objectMap = new HashMap<>();
    private SingletonManager(){

    }
    private static void registerService(String key,Object instance){
        if(objectMap.containsKey(key)) {
            objectMap.put(key,instance);
        }
    }

    public static Object getService(String key){
        return objectMap.get(key);
    }
}

单例模式总结
优点
a.单例模式在内存中只有一个实例,减少内存开支,非常适合频繁的创建和销毁一个对象的场景
b.由于单例模式只生成一个实例,所以减少了系统的性能开支,使用永久驻留内存的方式来解决。
c.单例模式避免了对公共资源的多重占用。如读写文件操作等等。
d.单例模式可以在系统设置全局的访问点。
缺点
a.单例模式一般没有接口,扩展很困难,除了修改代码基本没有其他方法可以实现。
b.单例对象如果持有Context,那么很容易引起内存泄露,最好传递Application Context.

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值