• 单例模式


    作用


    保证一个类只有一个实例,并且向外提供一个访问点。

    应用场景


    windows中的任务管理器就是一个很典型的单例模式。

    读取配置文件的类一般只new一个对象,没必要在每次读取配置文件时重新new一个对象。

    网站计数器也采用单例模式,否则很难同步

    应用程序的日志文件通常只用一个对象来维护

    数据库链接池的设计也采用单例模式。

    文件系统也是一个单例模式,一个操作系统只能有一个文件系统。

    在Spring中,每个Bean默认是单例的,这样Spring容器易于管理。

    javaweb中的每个Servlet都是一个单例

    优点


     

    因为只产生一个实例,所以减少了系统开销。可以在系统设置全局访问点,优化共享资源访问。

    分类


    主要  

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

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

    其它

    • 双重检测锁式 (由于JVM的原因,有时会出现问题)
    • 静态内部类式(线程安全,调用效率高,可以延时加载)
    • 枚举单例(线程安全,调用效率不高,不能延时加载)

     举例


    • 饿汉式

    一上来就创建对象,立即加载,存在的问题就这个对象可能会一直用不到,白白浪费内存资源

    package com.dy.xidian;
    
    public class SingleDemo1 {
        //类初始化是立即加载对象
        //jvm只会将类加载一次,在加载类时就创建了一个实例
        private static SingleDemo1 instance = new SingleDemo1();
        //构造器私有化,不能被new对象
        private SingleDemo1(){
        }
        
        //对外提供一个访问接口,因为只有一个实例存在,所以线程安全
        public static SingleDemo1 getInstance(){return instance;}
    }
    • 懒汉式

    用时才创建对象,延时加载。因为加入了同步机制,所以调用效率不高

    package com.dy.xidian;
    
    public class SingleDemo2 {
        private static SingleDemo2 instance;
        private SingleDemo2() {
    
        }
        // 在调用的时候才会实例化一个对象
        // 存在竞态条件,应进行同步
        public static synchronized SingleDemo2 getInstance() {
            if (instance == null)
                instance = new SingleDemo2();
            return instance;
        }
    }
    •  双重检测锁实现

    将同步块放到了方法的内部,这样不仅能延时加载,而且提高的调用效率。但是由于编译器优化以及JVM底层内部模型原因,偶而会出现问题,不建议使用package com.dy.xidian;public class SingleDemo3     private static SingleDemo3 instance;

    private SingleDemo3() {
        }
    
        public static SingleDemo3 getInstance() {
            if (instance == null) {
          synchronized(SingleDemo3.class) {
            if (instance == null)
              instance = new SingleDemo3();
          }
        }
        return instance;
    } }
    • 静态内部类模式

    JVM初始化类SingleDemo4时并不会去初始话其内部内,所以避免了向饿汉式那样立即加载对象。

    只有真正调用getInstance(),才会加载内部类。加载类时是线程安全的,而final能保证内存中只有这样一个实例存在,兼备了高效调用与延迟加载的优势。

    package com.dy.xidian;
    
    public class SingleDome4 {
        private SingleDome4(){}
        
        private static class SingleClassInstance{
            private static final SingleDome4 instance = new SingleDome4();
        }
        
        public static SingleDome4 getInstance(){
            return SingleClassInstance.instance;
        }
    }
    • 枚举方式

    枚举类本来就是单例的,但是它不能延时加载

    package com.dy.xidian;
    
    public enum SingleDome4 {
        INSTANCE;
        String a = new String();
        // 处理方法
        public static void main(String[] args) {
            System.out.println(SingleDome4.INSTANCE);
            SingleDome4.INSTANCE.a = "ff";
            System.out.println(SingleDome4.INSTANCE.a);
        }
    }

     存在问题


    单例模式的关键点就是构造器私有化,但是通过反射机制将构造器变成可被外部调用,这样的话单例就会被破坏,对于这种情况解决方案如下。

    package com.dy.xidian;
    
    public class SingleDome4 {
        private static SingleDome4 instance;
            //在构造器中抛出异常
        private SingleDome4() {
            if(instance != null )
                throw new RuntimeException();
        }
    
        public synchronized SingleDome4 getInstance() {
            if (instance == null)
                instance = new SingleDome4();
            return instance;
        }
    }

    我们可以通过反序列化的方式产生多个的对象,如果一个单例对象被多次反序列化,那么该对象不再是单例的了,解决方案如下:

    package com.dy.xidian;
    
    import java.io.ObjectStreamException;
    import java.io.Serializable;
    
    public class SingleDome4 implements Serializable{
        private static SingleDome4 instance;
        private SingleDome4() {
            if(instance != null )
                throw new RuntimeException();
        }
    
        public synchronized SingleDome4 getInstance() {
            if (instance == null)
                instance = new SingleDome4();
            return instance;
        }
        
        //基于回调的,在反序列化时该方法会直接被调用,而不是去创建一个新对象
        private Object readResolve() throws ObjectStreamException{
            return instance;
        }
    }

      

     

  • 相关阅读:
    科学家质疑当今商用量子计算机的性能
    科学家研制出可模拟大脑信息处理的微芯片
    2014年电子科技市场衰退
    号外!CentOS 宣布加入红帽公司!
    hadoop,高富帅的玩具?
    成为Linux内核高手的四个方法
    分阶段事件驱动架构【SEDA】
    原型程式设计【原型语言】
    IOS7.1 企业应用 证书无效 已解决
    iOS7.1企业应用"无法安装应用程序 因为证书无效"的解决方案
  • 原文地址:https://www.cnblogs.com/xidongyu/p/5621992.html
Copyright © 2020-2023  润新知