美文网首页
小白算法_楔子

小白算法_楔子

作者: xuyefeng | 来源:发表于2020-05-25 14:49 被阅读0次

    前言

    笔者属于算法小白一枚,本系列文章属于算法的学习笔记,也希望能给算法小小白起到些许的指引作用。如果有算法大佬不小心点了进来,只能说一声抱歉打扰了。

    思考

    作为本系列文章的楔子,我们今天不讨论算法解题,而是来谈谈一个老朋友:单例模式。相信大家对单例是非常熟悉的,但是如果要让你手写单例呢?写起来磕磕碰碰还是娴熟流畅?你会写几种?分别有什么区别?现在大家都在往 kotlin 转,那么在 kotlin 里面使用 object 关键字实现的单例又采用的是哪种实现方式呢?笔者从事 android 开发多年,在几个互联网大厂的面试中,经历了两次手写单例的考验,所以在这里以手写单例为楔子,为后面的手写算法起一个抛砖引玉的作用。

    正文

    什么是单例模式

    在同一个进程中,有些时候我们需要某个类同时只保留一个对象,这个时候就应该考虑单例模式的设计。

    单例模式的特点

    • 单例模式只能有一个实例对象
    • 单例模式必须创建自己的唯一实例
    • 单例模式必须对外部提供这一实例

    单例模式的实现

    饿汉式

    public class Singleton {
    
        private static Singleton INSTANCE = new Singleton();
    
        private Singleton(){
        }
    
        public static Singleton getInstance(){
            return INSTANCE;
        }
    }
    

    优点:线程安全,使用没有延迟。
    缺点:类加载即初始化实例,内存浪费。

    面试官追问:为什么线程安全?

    1. 饿汉式本质上是使用的是静态变量。
    2. 在类加载的过程中,静态变量就会进行初始化。
    3. 静态变量只会初始化一次,并且被所有的对象所共享。

    懒汉式

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

    优点:懒加载节省资源,线程安全。
    缺点:线程同步存在性能损耗

    面试官追问:为什么采用双重锁检验?为什么使用 volatile 关键字?

    1. 线程同步是存在性能损耗的,我们只需要在实际创建对象的时候进行同步,而不需要同步多余的代码。
    2. 第一重校验不为 null 的时候,直接返回对象。否则准备创建对象,此时需要进行线程同步。
    3. 在创建对象之前还需要进行第二重校验,是为了确保等待同步的线程不会重复创建对象。
    4. 使用 volatile 关键字是为了禁止指令重排,确保对象初始化完全。

    静态内部类

    public class Singleton {
    
        private Singleton() {
        }
    
        private static class SingletonHolder {
            private static Singleton INSTANCE = new Singleton();
        }
    
        public static Singleton getInstance() {
            return SingletonHolder.INSTANCE;
        }
    }
    

    优点:懒加载节省资源,无性能损耗的线程安全

    面试官追问:如何实现的懒加载?为什么线程安全

    1. 静态内部类只有被调用的时候才会加载,满足懒加载。
    2. 静态内部类在加载的时候,jvm 会保证线程安全。

    总结

    单例模式的实现很多,我们这里只取精华,只讲重点。最关键的是在面试过程中,你是否可以在纯文本编辑的环境下娴熟的手写以上几种不同的单例,然后从容的告诉面试官它们之间的区别,最后再承受住面试官深挖的几个为什么。

    借一句古语,与诸君共勉:纸上得来终觉浅,绝知此事要躬行。

    一个小小的单例提醒了我们,在后面的算法学习中要脚踏实地的手写算法解题,切记不可只做头脑风暴。在大厂的高级职位面试过程中,面试官最喜欢做的就是让求职者手写点代码。不需要太多,也不需要太难,就已经可以看出很多东西了。两位求职者,一个手写起来娴熟流畅,代码强壮,格式工整。另外一个先不说测试用例是否通过,写的过程都磕磕碰碰。你是面试官,你会如何抉择呢?

    最后附上 kotlin 通过 object 关键字实现单例的字节码反编译出来的 java 源代码,跟你想的是否一样呢?

    public final class Singleton {
       public static final Singleton INSTANCE;
    
       private Singleton() {
       }
    
       static {
          Singleton var0 = new Singleton();
          INSTANCE = var0;
       }
    }
    

    相关文章

      网友评论

          本文标题:小白算法_楔子

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