设计模式 之 单例模式
最近工作时候,总觉得自己写的代码不能光会用就够了,更要了解这些代码的原理及机制,所以就抽出画原型的时间来专门看了看最基础也是最常用的单例模式。不过大多数文档都是在网上度的,所以可能有些部分回合网上有雷同的部分,大家海涵。
顾名思义,单例模式就是“一个实例”的意思,在JAVA中,单例模式的定义是“一个类有且仅有一个实例,并自行初始化并向整个系统提供”。单例模式的最大的好处在于可以保证在整个程序中只有一个实例,适合一些被频繁创造销毁的对象保持存在,可以减少内存的残留。不过也有很明显的问题,单例类的拓展性不大,一般只是应用到一些实体类之类的没有太多操作的类,第二,单例模式增加代码间的耦合度,使代码的可读性和独立性造成了影响。
基本的单例模式(懒汉模式):
package com.example.administrator.mylibrary; /** * Created by Administrator on 2016/6/2 0002. * author : czx */ public class Singleton { private static Singleton s; public static Singleton getinstance(){ if (s == null){ s = new Singleton(); } return s; } }这是目前被最多使用的单例模式,一次锁定且使用方便,被调用时候判断是否已经被初始化,如果没有就进行初始化。但是这个方法有很多缺点,其中最重要的是没法保证线程安全。当两个线程同时调用的时候,这个时候就没法保证只有一个实例了。
所以我们还有一些更加安全的方法来进行单例操作。
这时候我们可以用synchronized(线程锁)来帮助我们进行线程锁定,这样我们的对象在同一时间就只会有一个线程进行访问了。我们可以在懒汉模式的基础上简单的加一个线程锁,如下:
package com.example.administrator.mylibrary; /** * Created by Administrator on 2016/6/2 0002. * author : czx */ public class Singleton { private static Singleton s; public static synchronized Singleton getinstance(){ if (s == null){ s = new Singleton(); } return s; } }这样就可以简单的完成对线程的同步锁定,但是这种方法有个弊病就是,每次调用的时候都回去判断线程锁,这样既占用内存,又占用时间,所以一般不使用这样的方法。我们的想要的只是在初始化的时候去判断这个锁,那么我们就可以在判断是初始化的时候使用所(双重锁定模式):
package com.example.administrator.mylibrary; /** * Created by Administrator on 2016/6/2 0002. * author : czx */ public class Singleton { private static Singleton s; public static Singleton getinstance(){ if (s == null){ synchronized (Singleton.class){ if (s == null){ s = new Singleton(); } } } return s; } }
还有一种类似的方法也是可以达到这样的效果,那就是静态内部类方法:
package com.example.administrator.bargraphtest; /** * Created by Administrator on 2016/6/14 0014. * author : czx */ public class Singleton { private static class LazyHolder{ private static final Singleton INSTANCE = new Singleton(); } private Singleton(){} public static final Singleton getInstance(){ return LazyHolder.INSTANCE; } }
静态内部类的好处有很多,也很多的博主推荐这种方法。这里最大的好处是他既能保证线程的安全,又因为是静态内部类只能被调用一次,所以省去了判断线程锁的步骤,相对双重锁定法,节省了大量的时间。
最后还有一种很无赖的模式,饿汉模式。这种模式在你的项目运行时就直接把类对象全部实例化了,这样不管你是什么时候调用,都可以直接使用,是最省时间的一种单例模式,但是这种模式有一个最大的弊病,那就是它非常吃内存。因为你不管用不用到这个对象,他都已经实例化了,等于说如果你的对象从头到尾都没有被使用的话,饿汉模式给它分配的内存等于说一直被占用而被浪费,所以不是很推荐这种模式:
package com.example.administrator.bargraphtest; /** * Created by Administrator on 2016/6/14 0014. * author : czx */ public class Singleton { private static Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance(){ return instance; } }这里就把基本的单例模式介绍完了,虽然单例模式并不是非常好的设计模式,但是因为它十分简单并且有用,使它成为了非常火热的设计模式,但是应用单例模式会增加代码的耦合性这一点也不可避免,所以这个也算是因项目而异吧。