zoukankan      html  css  js  c++  java
  • 【GOF23设计模式】--单例模式

    • 核心作用
      • 保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
    • 常见应用场景
      • windows的任务管理器
      • windows的回收站
      • 项目中,读取配置文件的类
      • 网站的计数器,否则难以同步
      • 应用程序的日志应用,一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加
      • 数据库连接池的设计一般也是采用单例,因为数据库连接是一种数据库资源
      • ServletApplication内置对象
      • Servlet编程中每个servlet也是单例的
      • Spring中每个bean默认就是单例的,这样做的有点是spring容器可以管理
      • spring mvc框架/struts1框架,控制器对象也是单例
    • 单例模式的优点:
      • 由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决
      • 单例模式可以在系统设置全局的访问点,优化环共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理
    • 常见的五种单例模式实现方式
      • 主要:
        • 饿汉式(线程安全,调用效率高。但是,不能延时加载)
        • 懒汉式(线程安全,调用效率不高。但是,可以延时加载)
      • 其他:
        • 双重检测锁式(由于JVM底层内部模型原因,偶尔会出现问题,不建议使用)
        • 静态内部类式(线程安全,调用效率高。但是,可以延时加载)
        • 枚举单例(线程安全,调用效率高,不能延时加载)

     

    1、饿汉式实现(单例对象立即加载)

    1

        /**
         * 饿汉式单例模式
         * @author qjc
         */
        public class SingletonDemo1 {
        
            //类初始化时立即加载这个对象(没有延时加载的优势)。加载时,天然的是线程安全的!
            private static SingletonDemo1 instance = new SingletonDemo1();
            
            //构造私有防止外部创建对象
            private SingletonDemo1() {
            }
            
            //方法没有同步,调用效率高
            public static SingletonDemo1 getInstance(){
                return instance;
            }
        }

    小结:

    • 饿汉式单例模式代码中,static变量会在类装载时初始化,此时也不会涉及多个线程对象访问该对象的问题。虚拟机保证只会装载一次该类,肯定不会发生并发访问的问题。因此,可以省略synchronized关键字
    • 问题:

    如果只是加载本类,而不是要调用getInstance(),甚至永远没用调用,则会造成资源浪费

    2、懒汉式实现(单例对象延迟加载)

    2:

        /**
         * 懒汉式单例模式
         * @author qjc
         */
        public class SingletonDemo2 {
            
            //延迟加载,用的时候在创建
            private static SingletonDemo2 instance;
            
            //构造私有化
            private SingletonDemo2() {
            }
            
            //方法同步,调用效率低
            public static synchronized SingletonDemo2 getInstance(){
                if(instance==null){
                    instance = new SingletonDemo2();
                }
                return instance;
            }
        }

    小结:

    • 优点:
      • lazy load! 延迟加载,懒加载!真正用的时候才加载
    • 问题:
      • 资源利用率高了,但是每次调用getInstance()方法都要同步,并发效率较低。

    3、双重检测锁实现

    3

        /**
         * 双重检测锁实现单例模式
         * @author qjc
         */
        public class SingletonDemo3 {
            
            //延迟加载,用的时候在创建
            private static SingletonDemo3 instance;
            
            //构造私有化
            private SingletonDemo3() {
            }
            
            //方法同步双重校验锁
            public static synchronized SingletonDemo3 getInstance(){
                if(instance==null){
                    synchronized (SingletonDemo3.class) {
                        if(instance==null){
                            instance = new SingletonDemo3();
                        }
                    }
                }
                return instance;
            }
        }

    小结:

    • 说明:
      • 这个模式将同步内容下方到if内部,提供了执行的效率,不必每次获取对象时都进行同步,只有第一步才同步,创建了以后就没必要了。
    • 问题:
      • 由于编译器优化原因和JVM底层内部模型原因,偶尔会出问题,不建议使用。

    4、静态内部类实现方式(也是一种懒加载方式)

    4

        /**
         * 静态内部类实现单例模式
         * 线程安全、调用效率高、实现了延时加载
         * @author qjc
         */
        public class SingletonDemo4 {
            
            //构造私有化
            private SingletonDemo4() {
            }
            
            //final 可不加
            private static class SingletonClassInstance{
                private static final  SingletonDemo4 instance = new SingletonDemo4();
            }
            
            public static SingletonDemo4 getInstance(){
                return SingletonClassInstance.instance;
            }
        }

    小结:

      • 外部类有没static属性,则不会像饿汉式那样立即加载对象
      • 只有真正调用getInstance(),才会加载静态内部类。加载类时是线程安全的。instancestatic final类型,保证了内存中只有这样一个实例存在,而且只能被赋值一次,从而保证了线程安全性。
      • 兼备了并发高效率调用和延迟加载的优势!

    5、使用枚举实现单例模式

    5

        /**
         * 使用枚举实现单例模式
         * 没有延时加载
         * @author qjc
         */
        public enum SingletonDemo5 {
            
            //这个枚举元素,本身就是单例对象
            INSTANCE;
            
            //添加自己需要的操作
            public void singletonOperation(){
                
            }
        }

    小结:

    • 优点:
      • 实现简单
      • 枚举本身就是单例模式。由JVM从根本上提供保障!避免通过反射和反序列化的漏洞!
    • 缺点:
      • 无延迟加载
    • 问题:
      • 反射可以破解上面几种实现方式!(可以再构造方法中手动抛出异常控制)
      • 反序列化可以破解上面几种实现方式!
        • 可以通过定义readResolve()防止获得不同对象。
          • 反序列化时,如果对象所在类定义了readResolve(),(实际是一种回调),定义返回哪个对象。
  • 相关阅读:
    September 17th 2016 Week 38th Saturday
    【2016-09-16】UbuntuServer14.04或更高版本安装问题记录
    September 16th 2016 Week 38th Friday
    September 11th 2016 Week 38th Sunday
    September 12th 2016 Week 38th Monday
    September 10th 2016 Week 37th Saturday
    September 9th 2016 Week 37th Friday
    c++暂停
    八皇后问题
    ( 转转)Android初级开发第九讲--Intent最全用法(打开文件跳转页面等)
  • 原文地址:https://www.cnblogs.com/dooor/p/5297596.html
Copyright © 2011-2022 走看看