一、使用场景
单例设计模式是应用最广的设计模式,例如:当创建一个对象需要消耗过多的资源,如要访问IO或数据库等资源,这时就要考虑用单例模式;在一个应用中,应该只有一个ImageLoader实例,这个ImageLoader中又有线程池、缓存系统、网络请求等,很消耗资源,一般用单例模式。
二、如何实现
1、构造函数私有化。
2、通过静态方法或者枚举返回单例对象。
3、确保单例对象有且只有一个,尤其是在多线程环境下。
4、确保单例对象在反序列化下不会重新构建对象。
三、代码实现
1、饿汉单例模式
public class Singleton {
private static final Singleton instance=new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
2、懒汉式
懒汉单例模式的优点是单例只有在使用时才会初始化,在一定程度上节约了资源。缺点是第一次加载时需要及时进行实例化,反应稍慢,最大的问题是每次调用getInstance都进行同步,造成不必要的同步开销,不建议使用。
public class Singleton {
private static Singleton instance;
private Singleton(){
}
public static Synchronized Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
}
3、Double Check Load(DCL)
优点是既能在需要时才初始化单例,又能保证线程安全,且单例模式初始化时调用getInstance不进行同步锁。缺点是在第一次加载时反应稍慢,由于java 内存模型的原因偶尔会加载失败,在高并发环境下也存在一定缺陷,但是概率较小。除非代码并发场景较复杂,或者在JDK 6版本以下,否则该种模式一般满足条件。该种模式也是使用较多的模式。
public class Singleton {
private static Singleton instance=null;
private Singleton(){
}
public static Singleton getInstance(){
if(instance==null){
synchronized(Singleton.class){
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
}
}
4、静态内部类单例模式
此种方法解决DCL模式不能在线程并发复杂情况下使用问题,此为推荐使用模式。
public class Singleton {
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.singleton;
}
/**
*静态内部类
*/
private static class SingletonHolder {
private static fina lSingleton singleton=new Singleton();
}
}
5、枚举单例
此种方法写法简单,线程安全,并且防止反序列化重新生成对象。
publc enum SingletonEnum{
INSTANCE;
}
以上构建单例模式方法中,为了避免反序列化重新生成对象,加入以下方法
private Object readResolve() throws ObjectSteamException{
return instance;
}
6、使用容器实现单例
这种方式使得我们可以管理多种类型的单例,并且使用时可以用统一的接口进行获取操作,降低用户使用成本,也对用户隐藏了具体实现,降低了耦合度。
public class SingletonManager {
private static Map objMap = new HashMap();
private SingletonManager(){}
public static void registerService(String key,Object instance){
if(!objMap.containsKey(key)){
objMap.put(key,instance);
}
}
public static ObjectgetService(String key){
return objMap.get(key);
}
}
不管以哪种方式实现单例模式,其核心都是构造器私有化,并且通过静态方法获取唯一实例,在获取过程中必须保证线程安全、防止反序列化重新生成实例等问题。当然,选择那种方式,取决于项目本身。
网友评论