zoukankan      html  css  js  c++  java
  • 设计模式之单例模式

    核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。

    常见应用场景:

    1. 项目中读取配置文件的类,一般也只有一个对象。没必要每次使用配置文件的时候,都new一个对象去读取;
    2. 数据库连接池的设计一般是单利模式,因为数据库的连接是很耗资源的;
    3. 在servlet中的Application也是单利模式;
    4. 在Spring中,每个Bean都是单利的,这样的优点就是Spring容器可以去管理;
    5. 在Servet编程中,每个servlet也是单例的;
    6. springMVC中的控制器也是单例的;

    单例模式的优点:

      - 由于单例模式只生成一个实例,减少了系统性能开销,当一个对象产生需要消耗较多资源时,如读取配置文件、产生其他依赖对象时,则可以通过在启动时直接创建出一个对象,然后永久驻留内存的方式来解决

      - 单例模式可以在系统设置全局的访问点,优化环共享资源的访问

    常见的四种单例模式的实现方式:

      -饿汉式(线程安全,调用效率高,不能延时加载)

      -懒汉式(线程安全,调用效率不高,可延时加载)

      -静态内部类式(线程安全,调用效率高,可延时加载)

      -枚举单例(线程安全,调用效率高,不能延时加载,并且可以避免通过反射和序列化创建新对象)

    选用方式:

      单例对象占用资源少,不需要延时加载

        枚举式 好于 饿汉式;

      单例对象占用资源大,需要延时加载

        静态内部类式 好于 懒汉式;

    饿汉式

      实现类:

    /**
     * <p>
     * SingletonTest01 单例模式测试类:饿汉式
     * <p>*/
    public class SingletonTest01 {
        //类初始化装载的时候,初始化该对象(类初始化是天然的线程安全)
        private static SingletonTest01 instance = new SingletonTest01();
    
        // 私有的构造器
        private SingletonTest01() {
    
        }
    
        // 方法没有同步块,并发效率高
        public static SingletonTest01 getInstance() {
            return instance;
        }
    }

      测试类:

    public class Client {
    
        public static void main(String[] args) {
            SingletonTest01 s1 = SingletonTest01.getInstance();
            SingletonTest01 s2 = SingletonTest01.getInstance();
            
            System.out.println(s1);
            System.out.println(s2);
        }
    }

      测试结果:

      

      说明:

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

      缺点:

        如果加载了该类,但是在程序中没有调用getInstance(),或者永远没有调用,会造成资源浪费。

    懒汉式:

      测试代码:

    /**
     * <p>
     * SingletonTest02 单例模式:懒汉式
     * <p>*/
    public class SingletonTest02 {
    
        //类初始化装载的时候,不初始化该对象(延时加载,真正使用的时候再创建)
        private static SingletonTest02 instance;
    
        private SingletonTest02() {
    
        }
        //方法需同步保证线程安全,调用效率低
        public static synchronized SingletonTest02 getInstance() {
            if (instance != null) {
                return instance;
            } else {
                return new SingletonTest02();
            }
        }
    }

      测试类及测试结果同上!

      说明:实现了懒加载!

      缺点:由于每次都要同步,并发效率低!

    静态内部类实现方式:

      测试类:

    /**
     * <p>
     * SingletonTest03 静态内部类实现单例模式
     * <p>*/
    public class SingletonTest03 {
    
        private static class SingletonInstance {
            private static final SingletonTest03 instance = new SingletonTest03();
        }
        // 方法没有同步,调用效率高
        public static SingletonTest03 getInstance() {
            return SingletonInstance.instance;
        }
        private SingletonTest03() {
    
        }
    }

      说明:外部类没有static属性,则不会像饿汉式立即加载对象;只有在真正调用getInstance()才会加载静态内部类。由于加载类是线程安全的,instance是static final 类型,保证内存中只有一个实例存在,而且只能被赋值一次,从而保证线程安全性;所以静态内部类实现单例模式兼备了并发高效和懒加载双重优势

    枚举实现单例模式

    public enum SingletonTest04 {
        //枚举元素是单例对象
        INSTANCE;
        //添加自己的需要操作
        public String SingletonOperator(){
            return "连接到数据库实例";
        }
    }

      测试代码

    public class Client {
        public static void main(String[] args) {
            SingletonTest04 s1 = SingletonTest04.INSTANCE;
            SingletonTest04 s2 = SingletonTest04.INSTANCE;
            System.out.println(s1==s2);
            System.out.println(s1.SingletonOperator());
        }
    }

      说明:

        优点:实现简单;枚举本身就是单例模式,由JVM从根本上保证了线程安全,同时避免了反射和序列化的漏洞!

        缺点:没有懒加载

  • 相关阅读:
    sklearn 数据预处理1: StandardScaler
    Gitlab利用Webhook实现Push代码后的Jenkins自动构建
    Shell脚本-自动化部署WEB
    Jenkins可用环境变量以及使用方法
    Docker常用命令
    nginx中root和alias的区别
    gitlab+jenkins=自动化构建
    Spring Boot2.0:使用Docker部署Spring Boot
    Maven内置属性、POM属性
    navicat连接mysql出现Client does not support authentication protocol requested by server解决方案
  • 原文地址:https://www.cnblogs.com/parryyang/p/5794344.html
Copyright © 2011-2022 走看看