• java设计模式----单例模式


    目录

        1.使用单例模式的作用

      2.常见的应用场景

      3.单例模式的实现方式

      4.单例模式存在的问题及解决办法

        5.总结

    一、使用单例模式的作用

      

      单例模式:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。

    二、常见的应用场景

      1.Windows的任务管理器

      2.Windows的回收站

      3.操作系统的文件系统

      4.Servlet 中的Application作用域

      5.Spring中的每个Bean都是单例

      6.Servlet中每个Servlet都是单例

    三、单例模式的实现方式

      常见的五种实现方式:

      1.饿汉式(线程安全,调用效率高。但是不能延迟加载)

      2.懒汉式(线程安全,调用效率不高,但是可以延迟加载)

      3.双重检测锁式(由于JVM底层内部原因,偶尔会出现问题,不建议使用)

      4.静态内部类式(线程安全,调用效率高,可以延迟加载)

      5.枚举单例(线程安全,调用效率高,不能延迟加载)

      1、饿汉式

      

     1 package com.demo.singleton;
     2 /**
     3  * 饿汉式单例设计模式实现
     4  */
     5 public class Singleton1 {
     6     
     7     private static Singleton1 singleton = new Singleton1();
     8     //私有化构造方法
     9     private Singleton1(){}
    10     public static Singleton1 getSingleton(){
    11         return singleton;
    12     }
    13 }

      

      2、懒汉式

     1 package com.demo.singleton;
     2 /**
     3  * 懒汉式单例设计模式实现
     4  */
     5 public class Singleton2 {
     6     
     7     private static Singleton2 singleton;
     8     //私有化构造方法
     9     private Singleton2(){}
    10     public synchronized static Singleton2 getSingleton(){
    11         if(singleton==null){
    12             singleton = new Singleton2();
    13         }
    14         return singleton;
    15     }
    16 }

      3、双重检测锁(不推荐)

     1 package com.demo.singleton;
     2 /**
     3  * 双重检测锁实现单例设计模式
     4  */
     5 public class Singleton3 {
     6     
     7     private static Singleton3 singleton=null;
     8     //私有化构造方法
     9     private Singleton3(){}
    10     public static Singleton3 getSingleton(){
    11         if(singleton==null){
    12             Singleton3 sc;
    13             synchronized(Singleton3.class){
    14                 sc = singleton;
    15                 if(sc == null){
    16                     synchronized(Singleton3.class){
    17                         if(sc == null){
    18                             sc = new Singleton3();
    19                         }
    20                     }
    21                     singleton=sc;
    22                 }
    23             }
    24         }
    25         return singleton;
    26     }
    27 }

      4、静态内部类实现方式

     1 package com.demo.singleton;
     2 /**
     3  * 静态内部类实现单例设计模式
     4  */
     5 public class Singleton4 {
     6     private static class singleton{
     7         private static final Singleton4 singleton= new Singleton4(); 
     8     }
     9     private Singleton4(){}
    10     public static Singleton4 getSingleton(){
    11         return singleton.singleton;
    12     }
    13 }

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

     1 package com.demo.singleton;
     2 /**
     3  * 使用枚举实现单例模式
     4  */
     5 public enum Singleton5 {
     6     /**
     7      * 定义一个枚举元素,这个枚举元素本身就代表着一个单例
     8      */
     9     SINGLETON;
    10     //定义这个单例的操作
    11     public Singleton5 getSingleton(){
    12         return SINGLETON;
    13     }
    14 }

    四、单例模式出存在的问题及解决办法

      问题:

        1.反射可以破解上面几种单例模式(不包含枚举式)

     

    package com.demo.singleton;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    /**
     * 利用反射破解Singleton2单例
     * @author Administrator
     *
     */
    public class Client {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException  {
            //不使用反射破解的情况下
            Singleton2 s1 = Singleton2.getSingleton();
            Singleton2 s2 = Singleton2.getSingleton();
            System.out.println(s1==s2);
            //使用反射破解
            Class<Singleton2> clazz = (Class<Singleton2>) Class.forName("com.demo.singleton.Singleton2");
            Constructor<Singleton2> constructor = clazz.getDeclaredConstructor();
            constructor.setAccessible(true);
            Singleton2 i1 = constructor.newInstance();
            Singleton2 i2 = constructor.newInstance();
            System.out.println(i1==i2);
        }
    }

    解决方案:

    在Singleton2类中的私有化构造函数中判断是否存在这个对象,如果存在则手动抛出一个异常。

    package com.demo.singleton;
    /**
     * 懒汉式单例设计模式实现
     */
    public class Singleton2 {
        
        private static Singleton2 singleton;
        //私有化构造方法
        private Singleton2() throws Exception{
            if(singleton!=null){
                throw new Exception("只能创建一个实例");
            }
        }
        public synchronized static Singleton2 getSingleton() throws Exception{
            if(singleton==null){
                singleton = new Singleton2();
            }
            return singleton;
        }
    }

        2.反序列化可以破解上面几种单例模式(不包含枚举式)

    package com.demo.singleton;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    /**
     * 使用反序列化破解单例模式
     * @author Administrator
     *
     */
    public class Client2 {
        public static void main(String[] args) throws Exception {
            //序列化单例类
            Singleton2 s =Singleton2.getSingleton();
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("b.obj"));
            oos.writeObject(s);
            oos.flush();
            oos.close();
            //反序列化单例
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("b.obj"));
            Singleton2 s2 = (Singleton2)ois.readObject();
            ois.close();
            System.out.println(s==s2);
        }
    }

    解决方案:

    在序列化的方法里面定义一个readResolve()方法,在反序列化的时候会回调这个函数。

    package com.demo.singleton;
    
    import java.io.ObjectStreamException;
    import java.io.Serializable;
    
    /**
     * 懒汉式单例设计模式实现
     */
    public class Singleton2 implements Serializable{
        
        private static Singleton2 singleton;
        //私有化构造方法
        private Singleton2() throws Exception{
            if(singleton!=null){
                throw new Exception("只能创建一个实例");
            }
        }
        public synchronized static Singleton2 getSingleton() throws Exception{
            if(singleton==null){
                singleton = new Singleton2();
            }
            return singleton;
        }
        private Object readResolve() throws ObjectStreamException{
            return singleton;
        }
    }

     五、总结

      单例模式的优点:

      ——由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动

    时直接产生一个单例对象,然后永久驻留内存的方式来解决

      ——单例模式可以在系统设置全局的访问点,优化环共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理

      具体使用哪种单例模式:

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

      • 枚举式 好于 饿汉式

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

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

  • 相关阅读:
    养兔引起轩然大波,做事情执着的他竟做到了年产值3000万元
    凭良心用好料,做卫生包子让他的日营业收入近3000元
    肉牛养殖前景好,他尝到甜头带富了贫困户
    那些年,我们处理过的SQL问题
    windows右键没有新建选项的解决办法
    windows右键没有新建选项的解决办法
    IT服务,共享经济的下一个风口?
    IT服务,共享经济的下一个风口?
    IT服务,共享经济的下一个风口?
    IT服务,共享经济的下一个风口?
  • 原文地址:https://www.cnblogs.com/bananafish/p/9940709.html
Copyright © 2020-2023  润新知