美文网首页
设计模式之单例模式

设计模式之单例模式

作者: Berry_ad07 | 来源:发表于2018-07-11 11:21 被阅读0次

    对于单例模式,我想大家并不陌生,因为它是我们代码编写中比较常用的设计模式之一。

    不过,大家可能不知道的是,单例模式还有很多别样的编写方式。

    首先,先给大家说一下单例模式的几要素:

    1.定义一个自己私有的对象;

    2.定义一个私有的构造函数,使得外接不可以直接拿到对象本身;

    3.定义一个公共的静态方法,用于返回私有对象;

    4.只有在私有对象为空的时候才去new一次对象;


    然后,给大家分享下三种类型的单例模式:懒汉式,饿汉式以及登记式,这三种模式是对私有对象创建模式的一种分类。

    1.懒汉式

    所谓懒汉式,就是在需要创建对象的时候才进行创建。

    (1)普通懒汉式

    public class Singleton {

      private static Singleton instance;

      private Singleton () {}

      public static Singleton getInstance() {

          if (instance == null) {

               instance = new Singleton();

           }

           return instance;

        }

    }

    缺点:存在线程不安全性。在多线程环境下,如果多个线程同时实例化某懒汉式的单例类,那么就有可能在单例类内部多次初始化实例,造成单例模式失效。因此,对于多线程程序中的懒汉式单例,还需要对其加锁,确保线程安全。

    (2)线程安全的懒汉式

    a.无关对象锁

    public class Singleton {

      private static Singleton instance;

      private static Object syncLock = new Object();

      private Singleton () {}

      public static Singleton getInstance() {

        synchronize(syncLock) {

             if (instance == null) {

                  instance = new Singleton();

               }

              return instance;

            }

        }

    }

    b.当前对象锁

    public class Singleton {

      private static Singleton instance;

      private Singleton () {}

      public static Singleton getInstance() {

        synchronize(this) {

             if (instance == null) {

                  instance = new Singleton();

               }

              return instance;

           }

        }

    }

    c.类本身锁

    public class Singleton {

      private static Singleton instance;

      private Singleton () {}

      public static Singleton getInstance() {

         if (instance == null) {

            synchronize(Singleton.class) {

                 if (instance == null) {

                      instance = new Singleton();

                   }

                  return instance;

                }

            }

        }

    }

    说明:如上写了a b c三种线程锁的方式,目的在于告诉大家,b方式的线程锁在单例模式中是不可取的,原因是getInstance方法是一个静态方法,在它的内部不能使用未静态的或者未实例化的类对象(避免空指针异常);

    缺点:线程安全的懒汉式单例执行效率不如饿汉式

    (3)内部类形式的懒汉式

    public class Singleton {

      private Singleton () {}

      public static Singleton getInstance() {

           return Holder.SINGLETON ;

        }

        private static class Holder {

            private static final Singleton SINGLETON = new Singleton();

        }

    }

    说明:这种方式解决了上述的两种缺点,并优于饿汉式的空间换时间方案。

    2.饿汉式

    所谓饿汉式,就是类一编译及创建好私有对象。

    public class Singleton {

      private static Singleton instance = new Singleton();

      private Singleton () {}

      public static Singleton getInstance() {

           return instance;

        }

    }

    缺点:类一编译即占用一定的内存存储对象,不过效率优于线程安全的懒汉式单例。典型的空间换时间方案。

    3.登记式

    所谓登记式,就是将私有对象存放在特定的堆栈中,用于单例对象的分组,目前我还没发现使用的环境是啥,欢迎提出指导意见。

    //采用Map配置多个单例  

    public class Singleton {  

        // 设立静态变量,直接创建实例  

        private static Map map = new HashMap();  

        // -----受保护的-----构造函数,不能是私有的,但是这样子类可以直接访问构造方法了  

        //解决方式是把你的单例类放到一个外在的包中,以便在其它包中的类(包括缺省的包)无法实例化一个单例类。  

        protected Singleton() {  

            System.out.println("-->私有化构造函数被调用,创建实例中");  

        }  

        // 开放一个公有方法,判断是否已经存在实例,有返回,没有新建一个在返回  

        public static Singleton getInstance(String name) {  

            if (name == null) {  

                name = Singleton.class.getName();  

                System.out.println("-->name不存在,name赋值等于"+MySingleton3.class.getName());  

            }  

            if (map.get(name) == null) {  

                try {  

                    System.out.println("-->name对应的值不存在,开始创建");  

                    map.put(name, (MySingleton3)Class.forName(name).newInstance());  

                } catch (InstantiationException e) {  

                    e.printStackTrace();  

                } catch (IllegalAccessException e) {  

                    e.printStackTrace();  

                } catch (ClassNotFoundException e) {  

                    e.printStackTrace();  

                }  

            } else {  

                System.out.println("-->name对应的值存在");  

            }  

            System.out.println("-->返回name对应的值");  

            return map.get(name);  

        }  

        public Map getMap() {  

            return map;  

        }

    }

    相关文章

      网友评论

          本文标题:设计模式之单例模式

          本文链接:https://www.haomeiwen.com/subject/grvcpftx.html