设计模式之 - 单例模式

1. 预热

为了小伙伴们能够比较好的理解后面讲解,先将一些前置的概念在这里进行预热,假如你已经知道这里概念,你可以跳过这个小结。

  • 指令序重排:Java内存模型中,允许编译器和处理器对指令进行重排序,重排序过程不会影响到单线程程序的执行,会影响到多线程并发执行的正确性
  • volatile 可见性生命:通过加入内存屏障禁止重排序优化来实现
2. 实现方法分析

实现单例模式估计是全地球人都知道的设计模式了,它又有懒汉模式饿汉模式之分,区别在于对单例对象初始化的时机不同,懒汉模式顾名思义,比较懒,所以对象的初始化会放到使用的那一个刻才会进行!饿汉反之,具体孰好孰坏,这个得两说,就饿汉来说,如果单例对象比较轻(废话,要是很轻还用单例搞鬼么)和初始化比较快且后续一定使用的话,这个就无所谓了!比较推荐,但是如果不用,这样就有点浪费服务器的性能和资源了!接下来我会提供这两种模式的几种实现方式!

a) 懒汉模式

/**
 * 两种经典的饿汉式实现
 *
 * @author Lin.Jianfei
 * @version 1.0.0
 * @since 2018-05-07
 */
class Singleton4Eager1 {

    private Singleton4Eager1() {}

    private static Singleton4Eager1 INSTANCE = new Singleton4Eager1();

    public static Singleton4Eager1 getInstance() {
        return INSTANCE;
    }
}

class Singleton4Eager2 {
    private Singleton4Eager2() {}

    // 需要注意静态代码的顺序,静态代码块是按照编写的顺序执行
    private static Singleton4Eager2 INSTANCE = null;

    static {
        INSTANCE = new Singleton4Eager2();
    }

    public static Singleton4Eager2 getInstance() {
        return INSTANCE;
    }
}

b) 懒汉式

class Singleton4Lazy1 {
    private Singleton4Lazy1() {}

    private Singleton4Lazy1 instance = null;

    // 线程不安全
    public Singleton4Lazy1 getInstance() {
        if (instance == null) {
            instance = new Singleton4Lazy1();
        }

        return instance;
    }
}

class Singleton4Lazy2 {
    private Singleton4Lazy2() {}

    private Singleton4Lazy2 instance = null;

    // 线程安全,效率低下
    public synchronized Singleton4Lazy2 getInstance() {
        if (instance == null) {
            instance = new Singleton4Lazy2();
        }

        return instance;
    }
}

class Singleton4Lazy3 {
    private Singleton4Lazy3() {}

    // 这里加上 volatile 修饰,禁止指令优化重排
    private volatile Singleton4Lazy3 instance = null;

    // 线程安全,引入 volatile + 双重校验 改善并发性能,
    public synchronized Singleton4Lazy3 getInstance() {
        if (instance == null) {
            synchronized (Singleton4Lazy3.class) {
                if (instance == null) {
                    instance = new Singleton4Lazy3();
                }
            }
        }

        return instance;
    }
}

class Singleton4Lazy4 {
    private Singleton4Lazy4() {}

    private Singleton4Lazy4 instance = null;

    public Singleton4Lazy4 getInstance() {
        return InnerSingleton.INSTANCE.getInstance();
    }

    private enum InnerSingleton {
        INSTANCE;

        private Singleton4Lazy4 instance;

        // 利用虚拟机特性,保证延迟且只执行一次创建,避免的使用锁,性能最好
        InnerSingleton() {
            this.instance = new Singleton4Lazy4();
        }

        public Singleton4Lazy4 getInstance() {
            return this.instance;
        }
    }
}
3. 总结

这里,实现饿汉式有好多种方式可以实现,可以根据自己的业务场景需要进行选择,如果是单线程的场景,无疑是第一种最好,类似StringBuilder 和 StringBuffer。假如涉及到并发的话,建议采用最后用枚举方式的实现,即避免了锁的损耗且延迟加载!



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章