码迷,mamicode.com
首页 > 其他好文 > 详细

单例模式

时间:2019-06-17 23:03:08      阅读:120      评论:0      收藏:0      [点我收藏+]

标签:turn   new   多线程   顺序   首次加载   stat   cal   情况   需要   

单例模式(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;
    }
}

这即是双重检查锁。

单例模式

标签:turn   new   多线程   顺序   首次加载   stat   cal   情况   需要   

原文地址:https://www.cnblogs.com/xiangpeng/p/11042694.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!