单例模式

Posted xiangpeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式相关的知识,希望对你有一定的参考价值。

单例模式(Single Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。即需要隐藏其所有的构造方法,只能通过全局访问点来创建。

常见的单例有:ServletContext、ServletConfig、ApplicationContext、DBPool。

单例分为饿汉式单例,懒汉式单例,注册式单例,ThreadLocal单例。

饿汉式单例

饿汉式单例是指在单例类首次加载时就创建实例,缺点是:浪费内存空间。即不管用不用,也不管什么时候用,先创建,放着,占着内存空间。饿着,先吃饱。

public class HungrySingleton 
    
    //第一步,不管用不用,也不管什么时候用,先创建出来,占着内存空间
    private static final HungrySingleton instance = new HungrySingleton();
    
    //第二步,私有化构造方法,也即隐藏构造方法
    private HungrySingleton();
    
    //第三步,提供一个全局访问点,并返回创建的实例
    public static HungrySingleton getInstance()
        return instance;
    

第二种,高端一点的饿汉式单例

public class HungryStaticSingleton 

    //第一步,不管用不用,也不管什么时候用,先创建出来,占着内存空间
        private static final HungryStaticSingleton instance;
        
        static
            instance = new HungryStaticSingleton();
        
        
        //第二步,私有化构造方法,也即隐藏构造方法
        private HungryStaticSingleton();
        
        //第三步,提供一个全局访问点,并返回创建的实例
        public static HungryStaticSingleton getInstance()
            return instance;
        

这两种方式,都叫做饿汉式单例写法。
缺点:不管用不用,都初始化,如果大批量的采用这种写法,造成内存的浪费。

第二种为什么写在static块中呢?这是涉及到java的类加载机制,即:先静态后动态,先属性后方法,先上后下。所以写在static中,创建较快。

懒汉式单例

懒汉式单例是指先定义好类,被外部内调用的时候再创建实例。不用就一直不创建。

public class lazySimpleSingleton 
    // 第一步,先定义好
    private static lazySimpleSingleton instance;

    // 第二步,私有化构造方法,也即隐藏构造方法
    private lazySimpleSingleton() ;

    // 第三步,提供一个全局访问点,如果没有就创建
    public static lazySimpleSingleton getInstance() 
        if (instance == null) 
            instance = new lazySimpleSingleton();
        
        return instance;
    

优点:解决内存空间浪费的问题。但是风险是:有可能创建多个不同的实例(在多线程中可能创建多个不同的实例,也即违背了单例模式)。即饿汉式变成懒汉式有线程安全问题。产生的原因是:多个线程同时进入,同时判断,导致同时创建,也即创建了两个不同的对象。

解决方法,加锁

public class lazySimpleSingleton 
    // 第一步,先定义好
    private static lazySimpleSingleton instance;

    // 第二步,私有化构造方法,也即隐藏构造方法
    private lazySimpleSingleton() ;

    // 第三步,提供一个全局访问点,如果没有就创建
    public static synchronized lazySimpleSingleton getInstance() 
        if (instance == null) 
            instance = new lazySimpleSingleton();
        
        return instance;
    

加锁过后,执行new就有了顺序。

但是锁类,会发生阻塞,如果锁方法呢?

public class LazyDoubleCheckSingleton 
    // 第一步,先定义好
    private static LazyDoubleCheckSingleton instance;

    // 第二步,私有化构造方法,也即隐藏构造方法
    private LazyDoubleCheckSingleton() ;

    // 第三步,提供一个全局访问点,如果没有就创建
    public static LazyDoubleCheckSingleton getInstance() 
        //不是任何时候进来都要加锁,只有创建对象才加锁
        if(instance == null)
            //锁方法,不会发生阻塞
            synchronized (LazyDoubleCheckSingleton.class) 
                if (instance == null) 
                    instance = new LazyDoubleCheckSingleton();
                
            
        
        
        return instance;
    

这即是双重检查锁。

以上是关于单例模式的主要内容,如果未能解决你的问题,请参考以下文章

单例模式(单例设计模式)详解

Java模式设计之单例模式(二)

单例模式(饿汉式单例模式与懒汉式单例模式)

单例模式

单例模式

设计模式之单例模式