单例模式不难理解,就是在某些情况下,系统只需要获取一个相同的实例对象提供服务,这个时候,建立多个对象纯属浪费资源,比如:连接数据库,建立Session工厂,这个时候,工厂就一个就行,建多了也没用,这个时候可以使用单例模式。
正规定义就是:确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。
单利模式分为懒汉模式和饿汉模式。
懒汉模式是说,当需要实例对象的时候才创建这个实例对象,以后也使用这个推迟创建的实例对象,因为它是等需要才创建,所以它懒。
饿汉模式是说刚开始就创建实例对象,它着急创建,所以它饿,不管用不用,以后保留着这个实例对象等待使用。
示例代码:
SessionFactory类(空的,仅作实验用)
public class SessionFactory {
}
饿汉模式:
/****
* 饿汉模式
* @author wjw
*
*/
public class EagerSingleton {
private static final SessionFactory instance = new SessionFactory();
private EagerSingleton(){}
public static SessionFactory getInstance(){
return instance;
}
}
将构造方法设为私有是为了不让外界自己new新实例,给外界提供一个静态getInstance方法进行单例控制(懒汉模式相同)。
懒汉模式:
/*****
* 懒汉模式
* @author wjw
*
*/
public class LazySingleton {
private static SessionFactory sf = null;
private static Object object = new Object();
private LazySingleton(){}
public static SessionFactory getInstance(){
if(sf == null){
synchronized (object) {
if(sf == null){
sf = new SessionFactory();
}
}
}
return sf;
}
public static SessionFactory getErrorInstance(){
if(sf == null){
sf = new SessionFactory();
}
return sf;
}
}
getErrorInstance()是不进行多线程同步控制的懒汉模式,懒汉模式如果使用这个方法对外提供单例对象,多线程访问是不安全,有可能创建多个对象。
比如:某个线程进行完了null判断,为true,准备进入执行new对象操作,这个时候,线程运行权限给了另一个线程,另一个线程也来进行null判断,因为第一个线程还没创建对象就被抢走了执行权限,所以它的if判断也为true,也进入创建对象,这样就创建了多个对象,不符合单例模式原则:仅创建一个对象。
getInstance()进行了同步控制的懒汉模式,多线程访问的时候,判断为空,进入准备创建对象,同步代码块保证此时仅有一个线程访问里面语句。而为什么在同步代码块里还要再加一个if判断呢,这里有个词叫双重检查锁定,如果不做第二次检查,同步代码块就白做了。比如第一个线程判断为空准备进入同步代码块创建对象还没进,这时候线程运行权限被抢走,第二个线程判断也为空,也可以准备进入同步代码块创建对象,不加第二个if判断,两个线程将依次进入同步代码块中创建对象,做的工作都白做了。而加了第二个if判断,第一个线程创建了对象,第二个线程进入同步代码块在进行if判断不为null,不进行创建对象操作,才是真的符合单例模式原则。
Main类:
public class Main {
public static void main(String[] args) {
SessionFactory sf1 =EagerSingleton.getInstance();
SessionFactory sf2 =EagerSingleton.getInstance();
System.out.println(sf1 == sf2);
SessionFactory sf3 =LazySingleton.getInstance();
SessionFactory sf4 =LazySingleton.getInstance();
System.out.println(sf1 == sf2);
}
}
饿汉模式使用简单,但资源效率方面差于懒汉。但懒汉使用麻烦,且使用同步控制,延迟创建效率。
如有错误,欢迎指正
end