单例模式
2016-10-19 本文已影响0人
gaaaaaaaaaao
单例模式简单的讲就是保证一个类最多只有一个实例。
-
懒汉单例:即用到的时候再进行实例化。
public class SingleTon { private static SingleTon singleTon; private SingleTon() { } public static SingleTon getInstance() { if (singleTon == null) { singleTon = new SingleTon(); } return singleTon; } }
上述实现方式的缺陷是很明显的,即不是线程安全的。设想如下情况:线程1在运行到判断singleTon == null之后被切换到线程2,则线程2页会进行singleTon == null的判断,然后线程2创建了一个实例,然后切换回线程1,继续执行,还会创建一个实例。
-
懒汉修改1
public class SingleTon { private static SingleTon singleTon; private SingleTon() { } public static synchronized SingleTon getInstance() { if (singleTon == null) { singleTon = new SingleTon(); } return singleTon; } }
显然,线程安全问题被解决了,但是其实按照我们上面的分析,只有在第一次创建的时候才会出现线程安全问题,为此将整个代码段都加锁会导致每次调用的时候都是线程同步的,其他线程都是阻塞的,这样显然效率不是很高。
-
双重校验
public class SingleTon { private volatile static SingleTon singleTon; private SingleTon(){ } public static SingleTon getInstance(){ if(singleTon == null){ synchronized(SingleTon.class){ if(singleTon == null){ singleTon = new SingleTon(); } } } return singleTon; } }
这样就OK了,根据前面的分析,在有可能出现问题的部分加上锁,这样一来不仅能保证线程安全,还能保证效率。
-
静态内部类
public class SingleTon {private static class SingleTonHolder{ private static final SingleTon singleTon = new SingleTon(); } private SingleTon() { } public static SingleTon getInstance() { return SingleTonHolder.singleTon; } }
-
饿汉单例:即类初始化时就实例化
public class SingleTon { private static final SingleTon singleTon = new SingleTon(); private SingleTon() { } public static SingleTon getInstance() { return singleTon; } }
这样子的话根本不存在线程安全问题了。不过问题就是,一上来就实例化,不管是否使用。
总结:建议使用双重校验或静态内部类的方式实现。
优点:对于一些需要不断的创建实例并销毁的情景,单例模式很大程度减少了内存的开支,由于只有一个实例且常驻内存, 减少了系统开销去不断的生成新实例,而且由于只有一个实例,还能避免对资源的多重访问。
缺点:有一个实例常驻内存,会有一定的系统开销,另外由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。