设计模式之单例

2017-09-17  本文已影响0人  cpMark

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

使用场景:在某些特定场景下我们需要确保某个类有且只有一个对象,比如创建一个对象需要消耗的资源过多,如要访问IO或者数据库等;还有就是一些全局的配置应该只有一个单一实例,如果有多个,那么配置项在使用时到底使用哪个实例的配置,这样容易导致一些稀奇古怪的异常。

UML类图(以ImageLoader为例)
单例(ImageLoader).png

单例模式有如下几个关键点:

  1. 构造为private
  2. 通过静态方法getInstance()返回单例类的实例
  3. 注意在多线程环境下确保单例类的对象有且只有一个
  4. 确保单例类对象在反序列化时不会重新构建对象

补充:序列化和反序列化
序列化:将一个对象转为字节序列的过程称之为序列化(关键为ObjectOutputStream)
反序列化:将字节序列转为对象的过程称之为反序列化(关键为ObjectInputStream)

常见的创建单例的方式

  1. 饿汗式

/**
 * 普通员工
 */
class Staff1 {
    public void work() {

    }
}

/**
 * 副总裁
 */
class VP1 extends Staff1 {
    @Override
    public void work() {

    }
}

/**
 * CEO 饿汗式单例
 */
class CEO1 extends Staff1 {
    
    //先new出来
    private static final CEO1 sCeo = new CEO1();

    private CEO1() {}

    public static CEO1 getInstance(){
        //需要时直接返回
        return sCeo;
    }

    @Override
    public void work() {

    }
}

优点:节省运行时间
缺点:浪费空间,因为在类加载时就会创建实例

  1. 懒汉式
/**
 * CEO 懒汗式单例
 */
class CEO2 extends Staff2 {
    
    //声明私有的静态单例变量
    private volatile static CEO2 sInstance;

    private CEO2() {}

    /**
     * 懒汉式,双重保护锁机制
     * @return
     */
    public static CEO2 getInstance(){
       //避免不必要的同步,只有在实例未初始化的情况下才同步实例化(判断需不需要同步)
        if(sInstance == null){
            synchronized (Singleton02.class){
                //在null情况下才创建实例(判断需不需要实例化单例对象)
                if(sInstance == null){
                    sInstance = new CEO2();
                }
            }
        }

        return sInstance;
    }
}

优点:只有在使用时才会被实例化,在一定程度上节约了资源
缺点:(1)第一次加载时需要及时进行实例化,反应稍慢 (2)由于Java编译器允许处理器乱序执行,如果线程A先将声明对象sInstance指向分配的内存空间,然后才去调用单例的构造,初始化成员字段,在未初始化之前如果切换到线程B,由于取到的sInstance不为null,这样就会出现异常。不过JDK1.5给出里解决本问题的方式,就是在声明sInstance时前面加上volatile关键字。

  1. 静态内部类

/**
 * CEO 静态内部类实现单例
 */
class CEO3 extends Staff3 {
    private CEO3() {}

   public static CEO3 getInstance(){
       return CEO3Holder.sInstance;
   }


    /**
     * 静态内部类
     */
    private static class CEO3Holder{
        private static final CEO3 sInstance = new CEO3();
    }
}

解决了双重保护锁可能失效的情况

上一篇下一篇

猜你喜欢

热点阅读