在我们的系统中,有一些对象其实我们只需要一个,比如说:线程池、缓存、对话框、注册表、日志对象、充当打印机、显卡等设备驱动程序的对象。事实上,这一类对象只能有一个实例,如果制造出多个实例就可能会导致一些问题的产生,比如:程序的行为异常、资源使用过量、或者不一致性的结果。
使用单例模式的好处:
Spring 中 bean 的默认作用域就是 singleton(单例)的。 除了 singleton 作用域,Spring 中 bean 还有下面几种作用域:
单件模式:确保一个类只有一个实例,并提供一个全局访问点
// 用getInstance方法实例化对象,并返回这个实例
// 通过增加synchronized关键字到getInstance方法中,我们迫使每个
// 线程在进入这个方法之前,要先等候别的线程离开该方法。也就是说,
// 不会有两个线程可以同时进入这个方法。
public static synchronized Singleton2 getInstance() {
if (uniqueInstance==null){
uniqueInstance = new Singleton2();
}
return uniqueInstance;
}
同步会降低性能,只有第一次执行此方法时,才真正需要同步。换句话说,一旦设置好 uniquelnstance变量,就不再需要同步这个方法了。之后每次调用这个方法,同步都是一种累赘。
如果你的应用程序可以接受 getlnstance造成的额外负担,就忘了这件事吧。同步 getinstance的方法既简单又有效。但是你必须知道,同步一个方法可能造成程序执行效率下降100倍。因此,如果将 getinstance的程序使用在频繁运行的地方,你可能就得重新考虑了。
如果应用程序总是创建并使用单件实例,或者在创建和运行时方面的负担不太繁重,你可能想要急切( eagerly)创建此单件,如下所示。
public class Singleton3 {
// 利用一个静态变量来记录Singleton类对唯一实例
// 在静态初始化器中创建单件,这段代码保证了线程安全
private static Singleton3 uniqueInstance = new Singleton3();
// 把构造器声明为私有的,只有自Singleton类内才可以调用构造器
private Singleton3() {}
// 用getInstance方法实例化对象,并返回这个实例
public static Singleton3 getInstance() {
return uniqueInstance;
}
}
利用这个做法,我们依赖JVM在加载这个类时马上创建此唯一的单件实例。JWM保证在任何线程访问 uniquelnstancei静态变量之前,一定先创建此实例。
利用双重检查加锁( double- checked locking),首先检査是否实例已经创建了,如果尚未创建,“オ”进行同步。这样一来,只有第一次会同步,这正是我们想要的。
public class Singleton4 {
// 利用一个静态变量来记录Singleton类对唯一实例
// volatile并健词确保:当uniqueInstance变量被初始化成Singleton实例时,
// 多个线程正确的处理uniqueInstance变量
private volatile static Singleton4 uniqueInstance;
// 把构造器声明为私有的,只有自Singleton类内才可以调用构造器
private Singleton4() {}
// 用getInstance方法实例化对象,并返回这个实例
// 检查实例,如果不存在,就进入同步区
public static Singleton4 getInstance() {
// 只有第一次才彻底执行这里的代码。
if (uniqueInstance==null){
synchronized (Singleton4.class){
// 进入区块后,再检查一次,如果仍是null,才创建实例
if (uniqueInstance == null){
uniqueInstance = new Singleton4();
}
}
}
return uniqueInstance;
}
}
如果性能是你关心的重点,那么这个做法可以帮你大大地减少 getlnstanceo的时间耗费。
原文:https://www.cnblogs.com/rain1024/p/11783432.html