zoukankan      html  css  js  c++  java
  • 面试题,开发一个单例模式

    手写单例模式

      面试时候问道单例模式,单例模式时最简单的模式但是想要用好就得费一番力气

    饿汉模式

    public staticSingleton{
        private static Singleton = new Singleton();
        private Singleton(){}
        public static getSingleton(){
            return sinleton;
        }
    

      这样做得目的简单,但是无法做到延迟创建对象,但是我们很多时候都希望对象尽可能延迟加载,从而减小负担,所以懒汉模式如下

    public class Singleton{
        private static Singleton singleton = null;
        private Singleton(){}
        public static Singleton getSingleton(){
            if(singleton ==null){
                    singleton = new Singleton();
            }
             return singleton;
        }
    }
    

     考虑线程安全得写法:

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

      兼顾线程和效率得写法

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

      两次null 看试多余实际上提高了并发度,在单例模式中new的情况非常少,绝大多数进行并行读操作,因此多一次null,减少了绝大多的加锁的操作,执行效率提高的目的达到了。

    其他的坑

    volatitle 第一层意思被大家熟知,就是该变量工作内存中的修改会马上写入到主存。工作内存时线程独享。主存线程共享。 volatitle第二层意思禁止指令从排序优化。在jdk1.5之前无法保证线程安全。

    静态内部类模式

    那么,有没有一种延时加载,并且能保证线程安全的简单写法呢?我们可以把Singleton实例放到一个静态内部类中,这样就避免了静态实例在Singleton类加载的时候就创建对象,并且由于静态内部类只会被加载一次,所以这种写法也是线程安全的

    public class Singleton {
        private static class Holder {
            private static Singleton singleton = new Singleton();
        }
         
        private Singleton(){}
             
        public static Singleton getSingleton(){
            return Holder.singleton;
        }
    }
    

      枚举写法

    public enum Singleton {
        INSTANCE;
        private String name;
        public String getName(){
            return name;
        }
        public void setName(String name){
            this.name = name;
        }
    }
    

      使用枚举除了线程安全和防止反射强行调用构造器之外,还提供了自动序列化机制,防止反序列化的时候创建新的对象。因此,Effective Java推荐尽可能地使用枚举来实现单例。

    总结

    最后,不管采取何种方案,请时刻牢记单例的三大要点:

    • 线程安全
    • 延迟加载
    • 序列化与反序列化安全
  • 相关阅读:
    《张艺谋这个人》较真
    《智能》是真智能
    《解密小米之互联网下的商业奇迹》
    《三毛。。。。》烂漫
    《盛典―― 诺奖之行》
    常用iOS、Mac框架和库及常用中文开发博客
    《人脸识别与人体动作识别技术及应用》
    《程序员第二步从程序员到项目经理》
    《信息安全导论》
    [leetCode]141.环形链表
  • 原文地址:https://www.cnblogs.com/dousil/p/12689892.html
Copyright © 2011-2022 走看看