单例模式 --- 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
创建单例最好的办法就是让类本身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且可以提供一个访问该实例的方法。
单例常用的有懒汉模式和饿汉模式,二者的区别就是什么时候初始化。
public class SingletonModel {
private final static SingletonModel INSTANCE = new SingletonModel ();
private SingletonModel (){}
public static SingletonModel getInstance(){
return INSTANCE;
}
}
这个就是饿汉模式,从代码中可以看到:
1.类的构造器是private的,也就是别的类中不能创建该类的实例化对象。
2.INSTANCE为静态的,类加载的时候就会初始化生成一个SingletonModel 的对象。
3.getInstance方法是静态的可以用类名称+getInstance获取类的对象。
4.所谓的饿汉模式的意思就是,已经迫不及待了,不管别人用不用,我先生成再说。
再看下懒汉模式:
public class SingletonModel {
private static SingletonModel singleton;
private SingletonModel () {}
public static SingletonModel getInstance() {
if (singleton == null) {
singleton = new SingletonModel ();
}
return singleton;
}
}
1.同上。
2.singleton是静态的,但是没有使用之前是null。
3.可以通过getInstance获取类的对象。
4.第一次调用getInstance的时候回new一个对象,之后singleton将不再是null,再次调用的时候将返回第一次生成的对象。
5.这个之所以叫懒汉是因为类初始话的时候它并没有生成对象,只有别人要使用了,才发现还没有类的对象,怎么办呢,赶紧生成一个呗,生成完了别人再要的时候就直接返回现有的,一劳永逸了。
当然,上边这两个例子是最简单的,也是最具有代表性的,同时也是最不常用的方式,之所所以不常用或者说不用的原因是,谁写的代码中还不涉及多线程,涉及到多线程后上面的示例明显就不能用了。
再看下面的这个示例:
public class SingletonModel { private static SingletonModel singletonModel; private static final Object object = new Object(); private SingletonModel() { } public static SingletonModel getInstance(){ if (singletonModel == null) { synchronized (object) { singletonModel = new SingletonModel(); } } return singletonModel; } }
同样继续分析:
1,2,3 大同小异基本上都是同上解释。
4.类中new了一个final的object对象,并且加了一个synchronized 的关键字,这样就可以保证在多线程的情况下不会出现异常。
synchronized 中的这个锁也可以换成SingletonMode.class,仁者见仁智者见智这两个作用都是一致的,起码到目前为止我没有发现不一致的地方(如有误请指出,谢谢)。
我在网上看到别人说的单例模式有很多种,我个人觉得最基本的除了懒汉和饿汉的区别外其余最大的区别在于线程安全和锁的问题,最少可以有有以下几种:
(1)将singletonMode定义为volatile。
(2)synchronized 加在方法上,当然这样是可以的,但是!这样锁的范围会有点大哦,一般情况要尽量的减少synchronized 中的代码,以便减少不必要的资源持有以及线程的阻塞问题。
你可以将(1)和(2)使用在懒汉和饿汉上,那又多了几种,只要分析清楚原理,怎么变化都是你自己的事情了,爱怎么用就怎么用。但是在具体使用的时候还是建议使用最后一种。
单例在spring中的使用:
spring中的bean在配置文件可以分为prototype(多例)和singleton(单例)这两种,单例就是我们刚才说的只有一个实例对象,而多例就是我们平时用的用一个new一个。
spring中具体怎么创建单例这个就不说了,查一下就清楚了,比较简单。
为什么要使用单例,我个人认为如果对bean不加以控制,频繁的新建以及销毁将会影响系统的性能,一个两个不明显,但是要是一千个一万个呢,怎么就会影响到系统的性能呢,因为在创建的bean对象在内存中吧,内存jvm在管理吧,那jvm是不是需要GC,频繁的GC是不是会影响性能。
总的来说,一个单子模式涉及到线程安全、涉及到对象创建在JVM内存中是怎么存储的,涉及到GC,从根本上考虑,而不仅仅是两个例子记住就行。
不积跬步无以至千里,送给自己,谨记!