# __ .______ __ __ .______ .___________. ______ ______ .___ ___. # | | | _ \ | | | | | _ \ | | / | / __ \ | \/ | # | | | |_) | | |__| | | |_) | `---| |----` | ,----'| | | | | \ / | # | | | ___/ | __ | | ___/ | | | | | | | | | |\/| | # | | | | | | | | | | | | __ | `----.| `--' | | | | | # |__| | _| |__| |__| | _| |__| (__) \______| \______/ |__| |__| # ""$o o$"" ""$o o$" o "$""""o "o $" o""" $" "$o "$o" $o " $ o$" "$o $$$o$$$$o$$$$ $" "oooo o "" ""$$$$$$$$""o"" oo oooo" "$$$$$$oo"oo$$$o" o$$$$oo" o$$$o "o$$$$$$$ "$ $$$$$$$$$oo o$$$$$$$$$o"$" $ $$$ $$$$$$ o$$$$$$ "$$o"o $ $$$$o $$$$$$ $$$$$$$ $$$$o"o $ $$$$$ $$$$$" "$$$$$ $$$$$$ $ $o""""" """" """ """"""$" $ o$$$$$"""$$$$$"$$$$$""$$$$$ooo"o $ o"$o $$$$$$$$oo$$$$$$$$o $$"" $ oo$ "$$$$$$$$$$$$$$$$$$$$" o" o $oo o$$$"$ $$o"o $$$$$$$"" "$$$$$$$ o$$ $$$$o IPHPT BUG o$$$$" $ $$$$ o "$$$$$oo o$$$$$$ "o$$$$ $ $$$$$ o$$"" $ $$$$$o" "$$$$$$$$$$$$$ o o$$$$$o$ "" $$ $$" $ $$$" o"o$$$$$$$$$$$$ " "$$$ $ $$o o$$ "o $$ " $$$$$$$$$$$"o "$$ $ $$$ $$$ oo$ $ o""$$""$$$o " $"o$o $$$o o$$$$ o$$$"o"$oo$$$$o" o $o $$$$$oo$ $$$$o $$$$ $$$$ $$$$" $ $$$$$"" $$ o$$$ """$$$$"o" "$$$o "$$$o $$$" o """ $ $$$oo $$$$o" $$ o$$$"o" """"$ o$$$ o$" $$$ $ "$"" o$"o"$$o$$$$ "$$"o" o$$ "$oo $ " $$o $ "oo$"o$$$"o$o"$$$$o" o" $$$ ""$o $$ $$$o "o$$o$"$$"$$o$$o$$"$$o" $$$ ""o $$$ ""$$$ $$$$$$ $$$$ $" $$$$ $$ $$$$ $$$$"$$$o$ $"" $$$ $$$$ "$$$ """ $$$$ $$"" "$$ oo$" $ooo $ "$$ 单例模式   -  知芯

单例模式

  • 动机 在软件系统中有些特殊的类,必须保证只有一个实例,才能保证逻辑正确性以及良好的效率。如何绕过常规的构造器,来提供一种机制保证一个类只有一个实例。

  • 定义 保证一个类仅有一个实例,并提供一个该实例的全局访问点。

  • 懒汉模式

    public class Singleton1 {
        private static Singleton1 instance = null;
        private Singleton1() {
        }
        // 1、适用于单线程环境(不推荐)
        public static Singleton1 getInstanceA() {
            if (null == instance) {
                // 用到才构造,懒汉模式
                instance = new Singleton1();
            }
            return instance;
        }
        // 2、适用于多线程环境,但效率不高(不推荐)
        public static synchronized Singleton1 getInstanceB() {
            if (instance == null) {
                instance = new Singleton1();
            }
            return instance;
        }
        // 3、双重检查加锁,重排序会导致问题
        public static Singleton1 getInstanceC() {
            if (instance == null) {
                synchronized (Singleton1.class) {
                    if (instance == null) {
                        instance = new Singleton1();
                    }
                }
            }
            return instance;
        }
    }
    

    实现3逻辑上正确,但是由于编译器指令重排导致不安全(某一线程可能拿到一个不等于nullptr但是没有执行构造函数的 instance ),在Java平台可以对 instance 加上 volatile 使得整个赋值过程不能reorder;

    public class Singleton{
        private static class SingletonHolder{
            public static Singleton instance = new Singleton();
        }
        private Singleton(){}
        public static Singleton newInstance(){
            return SingletonHolder.instance;
        }
    }
    

    利用了类加载机制来保证只创建一个instance实例。与饿汉模式一样,不存在多线程并发的问题。 在应用中不使用内部类,JVM就不会去加载这个单例类,也就不会创建单例对象,从而实现懒汉式的延迟加载。 也就是说这种方式可以同时保证延迟加载和线程安全。

  • reorder instance=new Singleton(); 这行代码逻辑上是先分配内存,再调用构造函数,再将内存地址复制给变量名;重排之后可能先申请内存,然后就复制给名称,最后再调用构造函数。

  • 饿汉模式 eg. singleton in Spring-AOP

    public final class GlobalAdvisorAdapterRegistry {
    	private GlobalAdvisorAdapterRegistry() {
    	}
        // 事先构造好,饿汉模式
    	private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry();
    	public static AdvisorAdapterRegistry getInstance() {
    		return instance;
    	}
    	static void reset() {
    		instance = new DefaultAdvisorAdapterRegistry();
    	}
    }
    
  • 总结

    1. 饿汉模式线程安全,但是一开始就初始化,没有用到时造成浪费,适合内存占用小且一定会使用的情况。
    2. 实现线程安全的singleton,注意检查双检查锁的正确实现。
    3. 不使用锁和双重检查,最好使用内部类的方式。
    4. 另外基于枚举实现单例能解决序列化的问题。

欢迎转载,但请附上本文地址: http://www.codeyourlife.cn/detail/2/

理想和现实,他们是两种人,而我处于两者之间。有时激情昂扬认为自己能改变世界,仔细想来,大多数人注定平凡。