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

    作用


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

    应用场景


    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;
        }
    }

      

     

  • 相关阅读:
    web服务器-Apache
    nginx优化
    nginx下载限速
    nginx-URL重写
    HDU 5358 First One 求和(序列求和,优化)
    HDU 5360 Hiking 登山 (优先队列,排序)
    HDU 5353 Average 糖果分配(模拟,图)
    UVALive 4128 Steam Roller 蒸汽式压路机(最短路,变形) WA中。。。。。
    HDU 5348 MZL's endless loop 给边定向(欧拉回路,最大流)
    HDU 5344 MZL's xor (水题)
  • 原文地址:https://www.cnblogs.com/xidongyu/p/5621992.html
Copyright © 2011-2022 走看看