Android面试专题

设计模式之单例模式: 4种单例模式你都掌握了吗?

2018-07-10  本文已影响0人  阿粒_lxf

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意:

单例模式它有以下几个要素:

饿汉式单例模式

public class Hungry {
    private final static Hungry hungry = new Hungry();

    private Hungry() {}

    public static Hungry getHungry() {
        return hungry;
    }
}

饿汉式单例模式的好处:
    它是在类加载的时候就立即初始化,并且创建单例对象,没有加任何的锁、绝对线程安全,在线程还没出现以前就是实例化了,不可能存在访问安全问题,执行效率比较高,在用户体验上来说,比懒汉式更好。
    
饿汉式单例模式的缺点:
    类加载的时候就初始化,不管你用还是不用,都占着空间浪费了内存,有可能占着茅坑不拉屎。

懒汉式单例模式

public class SafeDoubleCheckedLocking {
    //volatile 防止指令重排序 内存可见性、
    private static volatile SafeDoubleCheckedLocking safeDoubleCheckedLocking = null;

    private SafeDoubleCheckedLocking() {}
    
    public static SafeDoubleCheckedLocking getInstance() {
        if(safeDoubleCheckedLocking == null) {
            synchronized (SafeDoubleCheckedLocking.class) {
                // 第一个线程已经创建了,第二个线程无需在创建 故此第二重判断
                if(safeDoubleCheckedLocking == null) {
                    //这里有指令重排序的可能
                    /**
                     * memory = allocate();   //1:分配对象的内存空间
                     * ctorInstance(memory);  //2:初始化对象
                     * instance = memory;     //3:设置instance指向刚分配的内存地址
                     * <p>
                     * memory = allocate();   //1:分配对象的内存空间
                     * instance = memory;     //3:设置instance指向刚分配的内存地址
                     * 注意,此时对象还没有被初始化!
                     * ctorInstance(memory);  //2:初始化对象
                     */
                    safeDoubleCheckedLocking = new SafeDoubleCheckedLocking();
                }
            }
        }
        return safeDoubleCheckedLocking;
    }

}

懒汉式单例模式的好处:
    在使用该类的时候在初始化对象,不会对内存造成浪费。
    
懒汉式单例模式的缺点:
    加synchronized同步锁的,性能就会受到影响。

注:双重检验锁是面试经常提问到的事,大家切记要搞懂。

懒汉式单例内部类模式(算是懒汉式单例模式改进版)

public class LazyPromote {

   // private static boolean initialized = false;
    //默认使用LazyThree的时候,会先初始化内部类
    //如果没使用的话,内部类是不加载的
    
    private LazyThree() {
        /*synchronized (LazyThree.class) {
            if (initialized == false) {
                initialized = !initialized;
           } else {
                throw new RuntimeException("单例已被侵犯");
            }
       } */
    }

    //每一个关键字都不是多余的
    //static 是为了使单例的空间共享
    //final 保证这个方法不会被重写,重载
    public static final LazyPromote getInstance() {
        //在返回结果以前,一定会先加载内部类
        return LazyHolder.LAZY;
    }

    //默认不加载
    private static class LazyHolder {
        private static final LazyThree LAZY = new LazyPromote();
    }
}

懒汉式单例内部类模式改进版
    特点:在外部类被调用的时候内部类才会被加载,内部类一定是要在方法调用之前初始化,巧妙地避免了线程安全问题这种形式兼顾饿汉式的内存浪费,也兼顾synchronized性能问题,完美地屏蔽了这两个缺点,史上最牛B的单例模式的实现方式.

注册登记式单例

public class BeanFactoryNew {


    private BeanFactoryNew() {
    }

    //线程安全
    private static Map<String, Object> ioc = new ConcurrentHashMap();

    public static synchronized <T> T getBean(Class<T> className) {

        if (!ioc.containsKey(className.getName())) {
            T obj = null;
            try {
                obj =className.newInstance();
                ioc.put(className.getName(), obj);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return obj;
        } else {
            return (T)ioc.get(className.getName());
        }

    }
}
上一篇 下一篇

猜你喜欢

热点阅读