设计模式-单例模式及其拓展

zhy

发布于 2020.02.29 13:07 阅读 2580 评论 0

单例模式: 指一个类只有一个实例,且该类能自行创建这个实例的一种模式。

 

单例模式的用途:

     1. 一个类只生成一个对象,可以节省内存资源、保证数据内容的一致性,避免出现当某类需要频繁实例化,而创建的对象又频繁被销毁的情况。

     2. 适用于对象需要被共享的场合。共享对象可以有效节省内存,提高访问效率。

   

单例模式可以分为懒汉模式和饿汉模式:

 

class Singleton{
      private static volatile Singleton single;
      
      private static Singleton(){}

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

 

这是懒汉模式,只有当第一次调用getInstance()的时候才会初始化对象,可以避免浪费内存;但是加锁降低了执行效率。

 

class SingleObj{
    //私有变量 
    private static SingleObj single=new SingleObj();          
   //私有构造函数 不能被实例化  
    private static SingleObj(){}

    public static SingleObj getInstance(){
    return single;    
  }      
}

 

这是饿汉模式,其特点是类加载的时候就初始化,执行效率高(没有锁),但有时会出现从来没用过的情况,这样会浪费内存。

 

这里可能有人会想,有没有一种即高效又安全,避免浪费内存的方法呢。这就是双重锁判读机制:

/**
*Double CheckLock实现单例
*/

public class SingletonThree {
    
private volatile static SingletonThree instance;

//私有化构造器
private SingletonThree() {
}

//双重锁判断机制
public static SingletonThree newInstance() {
    if (instance== null) {
        synchronized (SingletonThree.class) {
            if (instance== null) {
                instance= new SingletonThree();
            }
        }
    }
return instance;
    }
}

 

这是懒汉模式的一种改进,高效且安全,由于JVM底层模型原因,偶尔会出问题,不建议使用。

 

既然这种方法不可靠,于是便有了另外的方法(利用静态内部类实现):

/**
*静态内部类实现模式
*/
public class SingletonFour {
    // 静态内部类
    private static class SingletonClassInstance {
        private static final SingletonFour instance= new SingletonFour();
}

// 私有化构造器
    private SingletonFour() {

    }

//静态工厂方法
    public static SingletonFour getInstance() {
        return SingletonClassInstance.instance;
    }
}

 

利用静态内部类实现即安全又高效,有满足延时加载。

 

还有一种单例模式的优化方式(枚举实现):

 

public class SingletonFive {

    //私有化构造器
    private SingletonFive(){

    }
    //使用枚举
    private static enum Singleton{
        INSTANCE;

        private SingletonFive singleton;
        //JVM会保证此方法绝对只调用一次
        private Singleton(){
            singleton = new SingletonFive();
        }
        public SingletonFive getInstance(){
            return singleton;
        }
    }

//静态工厂方法
    public static SingletonFive getInstance(){
    return Singleton.INSTANCE.getInstance();
    }
}

 

这种方式线程安全,调用效率高,不能延时加载,可以天然的防止反射和反序列化调用,自动支持序列化机制,绝对防止多次实例化 。