• Java设计模式之单例模式,笔记完整到不敢想象


    单例模式:

    作用

    保证一个类只有一个实例,并且提供一个访问该实例的全局访问入口

    单例模式的常用

    1.Windows的任务管理器
    2.Windows的回收站,也是一个单例应用
    3.项目中的读取配置文件的对象
    4.数据库的连接池
    5.Servlet中的Application Servlet
    6.Spring中的Bean默认也是单例的
    7.SpringMVC Struts中的控制器

    单例模式的优点

    1.由于单例模式只生成一个实例,减少了系统给的性能开销,当一个对象需要产生时,当时消耗的资源较多。那么产生对象时构建的方式就可以通过单例去构建。
    2.单例模式存在全局访问点,所以可以优化共享资源访问。

    常见的单例模式的构建方法:

    1.饿汉式:线程安全 调用率高  但是不能延迟加载
    2.懒汉式:线程安全 调用率不高 但是可以延迟加载
    3.双重检测(double check )
    4.静态内部类(线程安全 可以延迟加载)
    5.枚举单例 线程安全 不可以延迟加载

    代码案例展示

    饿汉式

    /** 
    * 饿汉式: 
    *      类只要被加载就会被加载全局变量,所以饿汉式,会被及时加载。(没有懒加载 ) 
    *      并且存在天然的线程安全问题。 
    * @author 码歌老薛 
    * @date 创建时间 猴年马月 
    * @version 1.0 
    */  
    public class SingleHungry {  
     //提供静态的全局变量 作为访问该类实例的入口  
     private static SingleHungry sh = new SingleHungry();  
     /** 
    * 构造器私有 无法创建对象 
     */  
     private SingleHungry(){  
           
    }  
     /** 
    * 对外提供get方法获取 该类的实例 
    * @return 
     */  
    public static SingleHungry getInstance(){  
    return sh;  
     }  
    }  
    

      

     

    懒汉式

    /** 
     * 懒汉式: 
    *      全局变量初始化放到了实例化方法中,延迟产生对象。 
     *      但是当多个线程统一访问时,有可能出现线程不安全的情况。需要优化。 
     * @author 码歌老薛 
     * @date 创建时间 猴年马月 
     * @version 1.0 
    */  
    public class SingleLazy implements Serializable{  
       //提供静态的全局变量 作为访问该类实例的入口 但是这里不立即加载  
        private static SingleLazy sh = null;  
          
         
        /** 
         * 构造器私有 无法创建对象 
         */  
        private SingleLazy(){   
           System.out.println("构造函数被调用了");  
       }  
          
       /** 
         * 对外提供get方法获取 该类的实例 
        * @return 
        * @throws InterruptedException  
         */  
        public static synchronized SingleLazy getInstance() {  
           if(sh==null){  
                sh = new SingleLazy();  
           }  
            return sh;  
             
        }  
            
    } 

    上海尚学堂java培训 shsxt.com
     

    双重检测

    /** 
     * 懒汉式: 
     *      全局变量初始化放到了实例化方法中,延迟产生对象。 
     *      但是当多个线程统一访问时,有可能出现线程不安全的情况。需要优化。 
     * @author 码歌老薛 
     * @date 创建时间 猴年马月 
     * @version 1.0 
     */  
    public class SingleLazy4 {  
        //提供静态的全局变量 作为访问该类实例的入口 但是这里不立即加载  
        private volatile  static SingleLazy4 sh = null;  
          
          
        /** 
         * 构造器私有 无法创建对象 
         */  
        private SingleLazy4(){  
            System.out.println("被调用了");  
        }  
          
        /** 
         * 双重校验锁式(也有人把双重校验锁式和懒汉式归为一类)分别在代码锁前后进行判空校验 
         * ,双重校验锁式是线程安全的。然而,在JDK1.5以前,DCL是不稳定的,有时也可能创建多个实例, 
         * 在1.5以后开始提供volatile关键字修饰变量来达到稳定效果。 
         * 双重校验锁DCL(double checked locking) 
         * @return 
         * @throws InterruptedException  
         */  
        public static SingleLazy4 getInstance() {  
            if(sh == null){  
                synchronized(SingleLazy4.class){  
                    if(sh == null){  
                        sh = new SingleLazy4();  
                       //return singleton;    //有人提议在此处进行一次返回  
                    }  
                    //return singleton;    //也有人提议在此处进行一次返回  
                }  
            }  
            return sh;  
        }  
    }  
    
    上海尚学堂Java培训 shsxt.com 获取更多java学习资料
     

    静态内部类

    /** 
     *静态内部类 
     *
     * @author 码歌老薛
     * @date 创建时间 猴年马月 
     * @version 1.0 
     */  
    public class SingleInner {  
          
        /** 
         *静态内部类式和饿汉式一样,同样利用了ClassLoader的机制保证了线程安全; 
         *不同的是,饿汉式在Singleton类被加载时(从代码段3-2的Class.forName可见) 
         *就创建了一个实例对象,而静态内部类即使Singleton类被加载也不会创建单例对象, 
         *除非调用里面的getInstance()方法。因为当Singleton类被加载时 
         *,其静态内部类SingletonHolder没有被主动使用。只有当调用getInstance方法时, 
         *才会装载SingletonHolder类,从而实例化单例对象。 
     
        这样,通过静态内部类的方法就实现了lazy loading,很好地将懒汉式和饿汉式结合起来, 
        既实现延迟加载,保证系统性能,也能保证线程安全  
         */  
        private static class SingleInnerHolder{  
            private static SingleInner instance = new SingleInner();  
        }  
          
        private SingleInner(){  
            System.out.println("我被调用了");  
       }  
        public static SingleInner getInstance(){  
            return SingleInnerHolder.instance;  
        }  
    }  
     

    枚举单例

    /** 
     * jvm提供底层保证  
     * 不可能出现序列化、反射产生对象的漏洞 但是不能做到延迟加载 
    在外部,可以通过EnumSingleton.INSTANCE.work()来调用work方法。默认的枚举实例的创建是线程安全的 
    、,但是实例内的各种方法则需要程序员来保证线程安全。 
    总的来说,使用枚举单例模式,有三个好处: 
     1.实例的创建线程安全,确保单例。2.防止被反射创建多个实例。3.没有序列化的问题。 
     * @author 码歌老薛 
     * @date 创建时间 猴年马月 
     * @version 1.0 
     */  
    public enum SingleEnum {  
        //实例化对象  
        INSTANCE;  
          
        /** 
         * 对象需要执行的功能 
         */  
        void getInstance(){  
              
        }  
    }  

    上海尚学堂java培训 shsxt.com
     

    反射/序列化 获取对象 以及防止方式

    import java.io.ObjectStreamException;  
    import java.io.Serializable;  
      
    /** 
     * 懒汉式: 
     *      全局变量初始化放到了实例化方法中,延迟产生对象。 
     *      但是当多个线程统一访问时,有可能出现线程不安全的情况。需要优化。 
     * @author 码歌老薛 
     * @date 创建时间 猴年马月 
     * @version 1.0 
     */  
    public class SingleLazy implements Serializable{  
        //提供静态的全局变量 作为访问该类实例的入口 但是这里不立即加载  
       private static SingleLazy sh = null;  
          
          
        /** 
         * 构造器私有 无法创建对象 
         */  
        private SingleLazy(){  
           if(sh!=null){  
                throw new RuntimeException();  
            }  
            System.out.println("构造函数被调用了");  
        }  
          
        /** 
         * 对外提供get方法获取 该类的实例 
         * @return 
         * @throws InterruptedException  
         */  
        public static synchronized SingleLazy getInstance() {  
            if(sh==null){  
                sh = new SingleLazy();  
            }  
            return sh;  
              
        }  
          
        private Object readResolve()throws ObjectStreamException{  
            return sh;  
        }  
          
    }  

    上海尚学堂java培训 shsxt.com
     

    用法总结:

    1、懒汉式效率是最低的。
    2、占用资源少 不需要延时加载  枚举优于 饿汉式
    3、占用资源比较多 需要延时加载 静态内部类 优于  懒汉式

    更多Java技术文章欢迎阅读上海尚学堂Java培训,免费试学和线上公开课培训课程等你学习。

  • 相关阅读:
    搭建企业级Docker Registry -- Harbor
    搭建私服-docker registry
    CentOS 7.2修改网卡名称
    tomcat错误日志监控脚本
    Openresty+Lua+Redis灰度发布
    Jenkins权限控制-Role Strategy Plugin插件使用
    Rsyslog日志服务搭建
    awk4.0对数组value排序
    Spring-IOC 在非 web 环境下优雅关闭容器
    Spring-IOC bean 生命周期之 Lifecycle 钩子
  • 原文地址:https://www.cnblogs.com/shsxt/p/10311332.html
Copyright © 2020-2023  润新知