单例模式(Singleton)

1.单例模式的定义
确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

2.单例模式的使用场景
确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象应该有且只有一个。例如,创建一个对象需要消耗的资源过多,如果访问IO和数据库等资源,这时就要考虑使用单例模式。

3.实现单例模式关键点:
1)构造函数不对外开放,一般为Private;
2)通过一个静态方法或者枚举返回单例类对象;
3)确保单例类的对象有且只有一个,尤其是在多线程环境下;
4)确保单例类对象在反序列化时不会重新构建对象。

4.饿汉模式
饿汉模式比较占空间,典型的以空间换时间.

private class EHanShi{
        //饿汉式,饿汉比较饿,刚开始就直接实例化了。 
        private static final EHanShi singleton = new EHanShi();

        //私有化构造函数,防止外部实例化
        private EHanShi(){

        }

        /**
          *提供一个全局方法,获取实例
          */
         public static EHanShi getInstance(){
             return singleton;
         }

    }

5.懒汉模式
懒汉模式是声明一个静态对象,并且在用户第一次调用getInstance时进行初始化,这种方式执行
效率比较低,典型的以时间换取空间。

public class LanHanShi {

        private static LanHanShi singleton = null;

        //私有化构造函数,防止外部实例化
        private LanHanShi(){

        }

        //加上同步锁synchronized是为了线程安全
        public static synchronized LanHanShi getInstance(){
            if(singleton == null){
                singleton = new LanHanShi();
            }
            return singleton;
        }
    }

6.双重检查加锁懒汉式
所谓双重检查加锁机制是指:并不是每次进入getInstance方法都需要同步,
而是先不同步,进入方法过后,先检查实例是否存在,如果不存在,才进入下面的
同步块,这是第一重检查。进入同步块过后,再次检查实例是否存在,如果不存在,
就在同步的情况下创建一个实例,这时第二重检查。

    /* 要使用关键字volatile:被volatile修饰的变量的值,将不会被本地线程缓存,所以对该变量的读写都是直接操作共享内存,从而去确保多个线程能正确处理该变量。*/

    public class DoubleCheckLockLanHanShi(){
        private volatile static DoubleCheckLockLanHanShi singleton = null;

        private DoubleCheckLockLanHanShi(){ 
        }

        public static DoubleCheckLockLanHanShi getInstance(){
            //第一重判断
            if(singleton == null){
                synchronized(DoubleCheckLockLanHanShi.class){
                    //第二重判断
                    if(singleton == null){
                        singleton = new DoubleCheckLockLanHanShi();
                    }
                }
            }
            return singleton;
        }
    }

7.Lazy initialization holder
更好的单例实现模式,既实现了延迟加载,又实现了线程安全,这里使用到java类级内部类,和多
线程缺省同步锁的知识。
类级内部类指的是:有static修饰的成员式内部类。没有static修饰的成
员式内部类称为对象级内部类,类级内部类可以定义静态的方法,相对于其外部类的成员,只有在
第一次被使用时才会被加载。
线程缺省同步锁:在某些情况下,jvm已经隐含的为您执行同步。由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时访问final字段时,在创建线程之前创建对象时,线程可以看见它将要处理的对象时。

public class BetterSingleton{
        private static class SingletonHolder{
            //静态初始化器,由JVM来保证线程安全
            private static BetterSingleton singleton = new BetterSingleton();   
        }

        //私有化构造函数,防止外部实例化
        private BetterSingleton(){
        }

        public static BetterSingleton getSingletonInstance(){
            return SingletonHolder.singleton;
        }
    }

8.枚举类型的单例

public enum EnumSingleton{
        //定义一个枚举类型的元素,它就代表类EnumSingleton的一个实例
        singleton;
        //单例可以有自己的操作
        public void singletonOperation(){
            //功能处理
        }
    }

9.使用容器实现单例模式

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

        private SingletonManager(){
        }

        public static void registerService(String key,Object instance){
            if(!objMap.containsKey(key){
                objMap.put(key,instance);
            }
        }

        public static Object getInstance(String key) {
            return objMap.get(key);
        }
    }

10.单例模式的优点
1)由于单例模式在内存中只有一个实例,减少了内存开销,特别是一个对象需要频繁创建、销毁时,而且创建于销毁时性能又无法优化,单例模式的优势就非常明显。
2)由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其它依赖对象时,则可以通过在用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
3)单例模式可以避免对资源的多重占用,例如一个写文件操作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
4)单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如,可以设计一个单例类,负责所有数据表的映射处理。

11.单例模式缺点
1)单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本没有第二种途径可以实现。
2)单例模式持有Context,那么很容易引发内存泄漏,此时需要注意传递给单例对象的Context最好是ApplicationContext。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值