Java设计模式之单例模式(饿汉式,懒汉式,静态内部类实现,枚举实现)

单例模式

1、概述:

确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一的实例。

2、三要点:

(1)某个类只能有一个实例
(2)必须自行创建这个实例
(3)必须自行向整个系统提供这个实例

3、实现:

public class Singleton(){
	private static Singleton instance=null;
	//构造函数私有化,使外界要new该类时,只能通过方法去创建实例。
	private Singleton(){
	}
	//静态公有工厂方法,检验实例的存在性并实例化自己,
	//然后存储在静态成员变量中。
	public static Singleton getInstance(){
		if(instance==null){
			instance=new Singleton();
		}
		return instance;
	}
}

注意:

(1)单例类的构造函数的可见性为private。
(2)提供一个类型为自身的静态私有成员变量。
(3)提供一个公有的静态工厂方法。

4、扩展
(1)饿汉式单例:着急于实例化类,在定义时便实例化单例类。

public class EagerSingleton(){
	//当类被加载时,静态变量instance会被初始化,此时类的私有
	//构造函数会被调用,单例类的唯一实例将被创建。
	private static final EagerSingleton instance=new EagerSingleton();
	//私有构造
	private EagerSingleton(){
	}
	public static EagerSingleton getInstance(){
		return instance;
	}
}

(2)懒汉式单例:对于实例化类呈懒惰态度,即实例化的时机在第一被引用时触发,在类进行加载时,不会将自己实例化(延迟加载技术)。

public class LazySingleton(){
	private volatile static LazySingleton instance=null;
	private LazySingleton(){
	}
	//synchronized关键字,确保任意时刻只有一个线程执行
	synchronized public static LazySingleton getInstance(){
		if(instance==null){
			instance=new LazySingleton;
		}
		return instance;
	}
}

发现synchronized锁住了整个方法,导致多线程高并发时,系统性能降低。解决办法:仅仅锁住instance=new LazySingleton。

 public static LazySingleton getInstance(){
		if(instance==null){
			synchronized(LazySingleton.class){
				instance=new LazySingleton;
			}
		}
		return instance;
}

虽然解决了性能问题,但是这样会存在对象不唯一的情况。
原因:当线程A和线程B同时调用getInstance方法时,两者都执行到instance==null,均通过判断,此时A进入锁定的代码区,B进行排队等待。当线程A执行完毕时,线程B并不知道此时实例已经创建,将继续创建新的实例。最后导致产生的实例不唯一。

解决办法:在被锁定的的代码块中再次进行instance==null的判断(双重检查锁定)

 public static LazySingleton getInstance(){
 		//第一重判断
		if(instance==null){
			synchronized(LazySingleton.class){
				//第二重判断
				if(instance==null){
					instance=new LazySingleton;
				}		
			}
		}
		return instance;
}

注意:使用双重检查锁定来实现懒汉式单例,需要在静态成员变量instance之前增加修饰符volatile,但volatile会屏蔽JVM所做的一些代码优化,可能会导致系统的运行效率降低,因此使用双重检查锁定来实现单例模式也不是一种完美的实现方式。
(3)静态内部类实现单例模式(推荐使用):懒加载,且保证线程安全。

静态内部类特点:当类进行装载的时候,静态内部类不会被装载。当使用到静态内部类的静态变量时,会导致静态内部类被装载,且只装载一次,JVM的加载机制保证了线程安全。

public class InnerSingleton(){
	private InnerSingleton(){}
	private static class InnerSingletonInstance(){
		private static final InnerSingleton INSTANCE=new Singleton();
	}
	private static getInstance(){
		return InnerSingletonInstance.INSTANCE;
	}
}

(4)枚举实现单例模式(最完美的单例实现方法,不过用得挺少):
以上的方法都声明了一个私有构造,但仍然能够被反射所破坏进行对象的创建。

Singleton instance1=Singleton.INSTANCE;
Singleton instance2=Singleton.INSTANCE;
//instance1与instance2两者相同

enum Singleton{
	INSTANCE;//Singleton的一个属性
}

5、使用场景:

(1)需要频繁地进行创建和销毁的对象。
(2)创建对象时耗过多或耗费资源过多,但又经常用到的对象。
(3)工具类对象,频繁访问数据库或文件的对象。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT学习小镇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值