码迷,mamicode.com
首页 > 其他好文 > 详细

漫说单例模式--宝宝成长记 你真的了解了吗?

时间:2020-12-04 11:13:40      阅读:5      评论:0      收藏:0      [点我收藏+]

标签:load   tin   private   efault   com   alac   宝贝   registry   sts   

  • 你就是单例
  • 你呱呱落地到这个世界的时候,这就是单例的产生,你是世界上唯一无二的存在。

    技术图片

    此时,你是父辈、祖辈的宝贝。他们都想和你亲近。

    技术图片

    public class Singleton {
        private final static Singleton INSTANCE = new Singleton();  //婴儿呱呱落地
    
        // Private constructor suppresses   
        private Singleton() {}
    
        // default public constructor
        public static Singleton getInstance() {  //每个人都想抱你,和你亲近,你也想很多人亲近。
            return INSTANCE;
        }
      }

    亲近就有两种:一种:别人想要抱你;另一种:你呼唤别人抱你。

    第一种称之为:Eager initialization,如上面的代码所示。另一种称之为Lazy initialization。代码如下所示:

    public class SingletonDemo {
        private static SingletonDemo instance = null;  //我很懒,你要想报我,你自己动手
    
        private SingletonDemo() {    }
    
        public static  SingletonDemo getInstance() {
            if (instance == null) {
                        instance = new SingletonDemo (); //你得到机会了。
            }
            return instance;
        }
    }
    1. 竞争的产生

      很多人想报你和你亲近,可你只有一个呀,这就产生了矛盾,这就需要你来控制谁可以来抱你了。这就需要synchronization来控制。

    public class SingletonDemo {
        private static SingletonDemo instance = null;
    
        private SingletonDemo() {    }
    
        public static synchronized SingletonDemo getInstance() {
            if (instance == null) {
                        instance = new SingletonDemo ();
            }
            return instance;
        }
    }

    为了让更多人可以抱你,你想出了更好的办法:

    public class SingletonDemo {
        private static volatile SingletonDemo instance = null;
    
        private SingletonDemo() {    }
    
        public static SingletonDemo getInstance() {
            if (instance == null) {
                            synchronized (SingletonDemo .class){
                        if (instance == null) {
                                            instance = new SingletonDemo ();
                                    }
                            }
            }
            return instance;
        }
    }

    当然,因为怕出现问题,你想出了更巧的办法:双重检查锁
    (Double-checked locking)

    public static Singleton getInstance() {
      if(singleton == null) {
         synchronized(Singleton.class) {
           if(singleton == null) {
             singleton = new Singleton();
           }
        }
      }
      return singleton;
    }

    上述方法存在一定的风险,你可以在方法上再加入synchronized。

    1. 太复杂了,扛不住了,那就简单一点吧
    public class Singleton {
       public final static Singleton INSTANCE = new Singleton();
       private Singleton() {
             // Exists only to defeat instantiation.
          }
    }

    然后你就可以直接使用了:

    Singleton singleton = Singleton.INSTANCE;
          singleton.dothis();
          singleton.dothat();
          ...
    1. 上面产生单例的方法都是静态的,可以使用动态的方式吗?

      使用register机制来动态完成单例的实例化。动态化我们首先想到了什么?对了,是反射。

    import java.util.HashMap;
    import org.apache.log4j.Logger;
    public class Singleton {
       private static HashMap map = new HashMap();
       private static Logger logger = Logger.getRootLogger();
       protected Singleton() {
          // Exists only to thwart instantiation
       }
       public static synchronized Singleton getInstance(String classname) {
          Singleton singleton = (Singleton)map.get(classname);
          if(singleton != null) {
             logger.info("got singleton from map: " + singleton);
             return singleton;
          }
          try {
             singleton = (Singleton)Class.forName(classname).newInstance();
          }
          catch(ClassNotFoundException cnf) {
             logger.fatal("Couldn‘t find class " + classname);    
          }
          catch(InstantiationException ie) {
             logger.fatal("Couldn‘t instantiate an object of type " + classname);    
          }
          catch(IllegalAccessException ia) {
             logger.fatal("Couldn‘t access class " + classname);    
          }
          map.put(classname, singleton);
          logger.info("created singleton: " + singleton);
          return singleton;
       }
    }

    为了更好的复用代码,我们该怎么做呢?封装!

    import java.util.HashMap;
    import org.apache.log4j.Logger;
    public class SingletonRegistry {
       public static SingletonRegistry REGISTRY = new SingletonRegistry();
       private static HashMap map = new HashMap();
       private static Logger logger = Logger.getRootLogger();
       protected SingletonRegistry() {
          // Exists to defeat instantiation
       }
       public static synchronized Object getInstance(String classname) {
          Object singleton = map.get(classname);
          if(singleton != null) {
             return singleton;
          }
          try {
             singleton = Class.forName(classname).newInstance();
             logger.info("created singleton: " + singleton);
          }
          catch(ClassNotFoundException cnf) {
             logger.fatal("Couldn‘t find class " + classname);    
          }
          catch(InstantiationException ie) {
             logger.fatal("Couldn‘t instantiate an object of type " + 
                           classname);    
          }
          catch(IllegalAccessException ia) {
             logger.fatal("Couldn‘t access class " + classname);    
          }
          map.put(classname, singleton);
          return singleton;
       }
    }

    封装完成后,我们可以使用了。

    import java.util.HashMap;
    import org.apache.log4j.Logger;
    public class Singleton {
       protected Singleton() {
          // Exists only to thwart instantiation.
       }
       public static Singleton getInstance() {
          return (Singleton)SingletonRegistry.REGISTRY.getInstance(classname);
       }
    }
    1. 如果有很多小孩,医院是如何管理的呢?

    技术图片

    可是有很多护士给宝贝护理,怎么保证我们家的宝宝得到照顾呢?保证一个护士负责一个婴儿就ok了

    护士classloader 婴儿instance

    private static Class getClass(String classname) 
                                             throws ClassNotFoundException {
          ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
          if(classLoader == null)
             classLoader = Singleton.class.getClassLoader();
          return (classLoader.loadClass(classname));
       }
    }
    1. 如何给婴儿包被褥呢?当脱掉一件后如果被包裹了两层就,不好了。为了避免这种情况,就需要检查包裹的效果了。
    import org.apache.log4j.Logger;
    public class Singleton implements java.io.Serializable {
       public static Singleton INSTANCE = new Singleton();
       protected Singleton() {
          // Exists only to thwart instantiation.
       }
          private Object readResolve() {  //保证包裹的检查返回同一种情况。
                return INSTANCE;
          }
    }

    参考:

    1. http://en.wikipedia.org/wiki/Singleton_pattern

    2. http://www.javaworld.com/article/2073352/core-java/simply-singleton.html

    3. 注意,以上图片均来自互联网,不一一标注了。

    漫说单例模式--宝宝成长记 你真的了解了吗?

    标签:load   tin   private   efault   com   alac   宝贝   registry   sts   

    原文地址:https://blog.51cto.com/15015181/2556815

    (0)
    (0)
       
    举报
    评论 一句话评论(0
    登录后才能评论!
    © 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
    迷上了代码!