Java单例设计模式

单例设计模式


一 为什么要使用单例设计模式


在程序开发中,单例模式尝尝被用于管理共享的资源。有的类的对象我们只需要一个,比如线程池,缓存,注册表的对象,如果有多个实例就会导致很多问题的发生。所有我们要设计一个类,确保这个类只有一个对象,并提供一个全局访问点。


二 饿汉单例设计模式

例子:

public class SingletonPractice{
	//单例设计模式。在内存中只允许一个对象---(static)
	public static void main(String[] args){
		//Single ss = new Single();// 错误类型显式:构造器不可见!!!!阻止了此次创建Single对象
		Single ss = Single.getInstance();
		Single ss1 = Single.getInstance();
		System.out.println("is the same object? " + (ss1 == ss));
	}
}
//饿汉单例设计模式
class Single{
	//(1)在类内创建本类的对象。在内存中,保证只有一个
	private static Single unique = new Single();
	//(2)私有化构造函数,防止在外部被新建对象
	private Single(){}
	//(3)提供公共的静态方法让用户可以得到对象(否则在外部只能通过对象才能拿到这个方法,与需求产生矛盾)
	public static Single getInstance() {
		return unique;
	}	
}

输出的结果:is the same object? true


三 懒汉单例设计模式


例子:

public class SingletonPractice2 {
	//单例设计模式,懒汉单例设计模式
	public static void main(String[] args){
		//Single ss = new Single();// 错误类型显式:构造器不可见!!!!阻止了此次创建Single对象
		Single ss = Single.getInstance();
		Single ss1 = Single.getInstance();
		System.out.println("is the same object? " + (ss1 == ss));
	}
}
class Single{
	//懒汉单例设计模式
	//对象也可以放到方法区的内存中(这样只有1个)
	//(1)先不初始化对象
	private static Single unique;
	//(2)私有化构造函数
	private Single(){}
	//(3)加入判断,如果没有这个对象存在,则创建
	public Single getInstance(){
		if (unique == null) unique = new Single();
		return unique;
	}
}

输出的结果:is the same object? true


分析:饿汉与懒汉单例设计模式的相同点都是将构造函数私有化(此时,只有这个类内点代码可以调用这个构造函数),且有一个全局访问点getInstance。区别在于,饿汉单例模式在类加载的时候就进行了初始化,而懒汉单例设计模式在调用getInstance的时候,进行了判断。


假如不加这个判断,那么在内存中会出现什么情况呢:



上面这幅图显示了不加判断的情况(红色直线代表第一次调用getInstance,绿色直线代表第二次调用getInstance), 我们可以看到,unique内存储的内存地址在第二次调用时发生了变化,指向了新的实例的内存地址。这样也就同时有两个实例存在了。


四 多线程情况下单例模式遇到的问题


假设使用懒汉单例模式时,在多线程下可能会发生下面这种情况:


线程1调用getInstance方法----------------->并进行判断------------->unique为空,允许创建---------->切换到了线程2,调用getInstance--------->进行判断-------

---------->unique为空,允许实例化--------->线程2实例化了对象---------------->切换到了线程1,线程1实例化了对象


上面这这种情况,就会同时存在两个实例,违背了我们的需求。处理这种情况,我们可以使用一种加锁的方式确保只有一个实例:

class Single{
	private static Single unique;
	private Single(){}
	public static Single getInstance(){
		if(unique == null){
			synchronized (Single.class){
				if(unique == null){
					unique = new Single();
				}
			}
		}
		else{
			System.out.println("对象已经存在");
		}
		return unique;
	}
}

分析:使用枷锁的方式有一个缺点,那就是只有在第一次执行此方法是,才需要同步。这样十分影响性能,同步一个方法可能会造成程序执行效率下降100倍。

所以在多线程的情况下,推荐使用饿汉单例设计模式(也存在缺点,在类加载时就实例化,浪费内存)


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值