美文网首页
放放学单例设计模式

放放学单例设计模式

作者: 追梦的汪星人哟 | 来源:发表于2018-07-08 22:54 被阅读7次

    放放是一个刚毕业的学生,性别男,爱好Java。
    放放的好朋友烬哥哥是一个优秀的架构师,看放放今天面色不太好
    烬哥哥:出啥事了?
    放放:面试官问了我,听过单例设计模式没?
    烬哥哥:这个你没答上来,不科学。
    放放:当然不是,面试官问了我更加深入的问题,你听我跟你港。

    面试场景:
    面试官:自我介绍一下。
    放放:巴拉巴拉。。
    面试官:看你简历上写到熟悉常见的设计模式,那你简单的说一下单例。
    放放:单例设计模式是。。。
    面试官:那你简单的手写一个。
    放放:那我就写个简单的。

    public enum Singleton{
      INSTANCE;
    public static Singleton getInstance(){
      return  INSTANCE;
      }
    }
    

    面试官:写的可以,不过一般写可能会用懒汉和饿汉,你能简单的写一下吗?
    放放:快速的写出来。。。

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

    面试官:很好,你这个懒汉式如果存在两个线程同时去调用getInstance方法,会产生两个instance吗?
    放放心想:故意卖破绽,上当了,嘻嘻。
    放放:当然了,并发的情况下有可能会产生多个对象。比如Thread1执行到

    if(null == instance)
    

    时间片用完,线程2开始执行也执行到上述条件下。
    此时切换到线程1执行,返回一个对象实例。再切换到线程2又返回一个实例。
    面试官:那该怎么解决呢?
    放放:共享资源竞争问题,当然先加锁咯。用Synchronized关键字。

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

    面试官:这样是可以,但是锁的力度太粗,效率很低。
    放放:

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

    放放:方法块去处理,粒度缩小了。双层检测来保证单例。第一个if保证非null的直接return不用经过加锁。第二个if是考虑到这样的情况。
    有两个线程同时运行到第一个if。然后线程1拿到锁new一个对象,这时候切换到线程2,也会拿一个对象。所以为了杜绝这样的情况。做第二个判断。
    面试官:这里还会出现一个问题你仔细想想。。
    放放:没毛病啊。
    面试官:静态变量需要加volatile关键字你知道为什么吗?
    放放:。。。
    面试官:(未完成!!!)
    面试官:那你能考虑写出一种不用synchronize的懒汉式单例吗?
    放放:。。。。。。
    面试官:好了,你回去等通知吧。

    场景回到现在:
    烬哥哥:原来是这样哦,放放啊,你不是看过《并发编程的艺术》吗?还记得CAS吗?
    放放:我靠,我当时怎么没想到。。。
    烬哥哥:

    public class Singleton {
        private static AtomicReference<Singleton> atomicReference = new AtomicReference<>();
        private Singleton(){}
        public static Singleton getInstance(){
            for(;;) {
                Singleton instance = atomicReference.get();
                if (instance != null) {
                    return instance;
                }
                instance = new Singleton();
                if (atomicReference.compareAndSet(null, instance)) {
                    return instance;
                }
            }
        }
    }
    

    烬哥哥:循环CAS来代替synchronized的锁,并发性更好点。缺点是:CAS消耗CPU大量的时间片。

    相关文章

      网友评论

          本文标题:放放学单例设计模式

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