Java设计模式之单例模式

1.前言

单例模式作为Java和Android中使用最广泛的设计模式,了解它对于我们设计出优秀的代码有很大的帮助。针对之前的文章进行更加详细的补充,也推荐大家前去学习《大话设计模式》和《Android源码解析和设计模式》这两本书。对于初学者学习设计模式很有帮助。

言归正传。

2.单例模式的定义

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

3.使用场合

不能自由构造对象的情况下(比如,某个类实例一次会消耗很多资源,如要访问IO和数据库资源,考虑使用单例模式)

4.单例模式特点

①构造方法(函数)被私有化(private);

②只能通过getInstance()方法取得Singleton(单例)类的实例化对象;

③不管外部如何操作,最终也只有一个实例化对象;

④在单例设计模式中一定会存在一个static方法,用于取得本类的实例化对象。

5.单例模式共有6种写法,它们各有利弊。

5.1 饿汉模式

   public class Singleton{
   	private static Singleton instance = new Singleton();//1
   	private Singleton(){

   	}

   	public staitc Singleton getInstance(){
   		return instance;
   	}


   }
类加载时就完成初始化(注释1),导致类加载慢,但获取对象速度快。该方式基于类加载机制,避免了多线程的同步问题。如果从始至终使用该实例,会造成内存浪费。

5.2 懒汉模式(线程不安全)

   public class Singleton{
   	private static Singleton instance;//声明一个静态对象
   	private Singleton(){

   	}

   	public staitc Singleton getInstance(){
   		if (instance == null) {
   			instance = new Singleton();
   		}
   		return instance;
   	}
   	
   }
懒汉模式是声明一个静态对象,并在用户第一次调用getInstance时进行初始化,上面的饿汉模式是在声明静态对象时就已经初始化。懒汉模式虽然节约了资源,但第一次加载时需要实例化,反应稍慢。且该懒汉模式无法在多线程下正常工作。

5.3 懒汉单例模式(线程安全)

public class Singleton{
	private static Singleton instance;//声明一个静态对象
	private Singleton(){}
	
	public static synchronized Singleton getInstance(){
		if(instance == null){
			instance = new Singleton();//第一次调用时初始化
		}
		return instance;
	}
}

该懒汉模式比起上面的多了一个“synchronized”关键字,正是因为它该模式才可以在线程中很好的工作,但是每次调用getInstance方法时都需要进行同步。这又会造成不必要的同步开销,大部分情况下并不会使用同步,所以该懒汉模式也是不推荐使用的。

5.4 单例模式之DCL(双重检查)单例模式(推荐使用)

public class Singleton{
  //在JDK是1.5或之后的版本,下面的①改为private volatile static Singleton mInstance = null;
 private static Singleton mInstance = null;//①
	private Singleton(){
		
	}
	public static Singleton getInstance(){
		//第一次判断为了避免不必要的同步
		if(mInstance == null){
			synchronized(Singleton.class){
				if(mInstance == null){
					//为了在null的情况下创建实例
					mInstance = new Singleton();
				}
			}
		}
		return mInstance;
	}
}

getInstance方法对mInstance进行了两次判空;第一次是为了不必要的同步,第二次是在Single等于null的情况下才去创建实例。使用volatile会影响性能,但考虑到程序正确性,牺牲的那点性能是值得的。

DCL的优点是资源利用率高。缺点是第一次加载时反应稍微慢一点,高并发环境下有一定的缺陷。但DCL也有着自己的问题,它在某些情况下会出现失效,称为DCL失效。一般这个时候会建议使用静态内部类单例模式来代替DCL模式。

5.5 静态内部类单例模式

//静态内部类单例模式
public class Singleton{
	private Singleton(){}
	public static Singleton getInstance(){
		return SingletonHolder.sInstance;
	}
	
	/**
	* 静态内部类
	*/
	private static class SingletonHolder{
		private static final Singleton sInstance = new Singleton();
	}
}
第一次加载Singleton类的时候不会初始化sInstance,只有第一次调用getInstance方法时虚拟机加载SingleHolder并初始化sInstance。这样既可以保证线程安全,又可以保证Singleton类的唯一性。该模式是推荐使用的单例模式。

5.6 枚举单例模式

   public enum Singleton{
   	INSTANCE;
   	public void doSomething(){
   		
   	}
   }
枚举单例在实际开发中很少会被使用,这里也不会过多介绍。


最后,还是那句老话:合适的才是最好的。选择模式前要仔细考虑下:是否为复杂的并发环境,是否需要控制单例对象的资源消耗等。考虑清楚再写。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值