场景
在学习Mybatis或者Hibernate中,有一个SqlSessionFactory对象。此对象属于重量级对象,消耗的资源比较大,也只需要存在一个即可。类似的对象还有,线程池、缓存、日志等。这种情况下,就可以使用单例模式来进行控制对象的创建,确保只存在一个。
饿汉模式
懒汉的的单例模式顾名思义就是,在使用前就已经完成的初始化。
代码:
public class HungrySingleton {
//类装载时就完成初始化
private static HungrySingleton hungrySingleton = new HungrySingleton();
//申明私有的构造方法,无法外部通过new初始化对象
private HungrySingleton() {
}
public static HungrySingleton getSingleton() {
System.out.println("获取单例对象");
return HungrySingleton.hungrySingleton;
}
}
这样的写法很简单,但由于在类装载时就完成了初始化,可能会造成一定的资源浪费,但是不存在多线程的问题,比较常见。
静态内部类
代码:
public class StaticHungrySingleton {
private StaticHungrySingleton() {
}
private static class Singleton{
private static final StaticHungrySingleton staticHungrySingleton = new StaticHungrySingleton();
}
public StaticHungrySingleton getSingleton() {
return Singleton.staticHungrySingleton;
}
}
相对于上面的方法,静态内部类实现了延迟加载的效果,当StaticHungrySingleton 调用getSingleton()方法时,才会触发静态内部类的初始化过程。
懒汉模式
饿汉模式是在类装载的时候就完成了初始化,懒汉模式在被调用的时候才进行初始化,不会造成内存的浪费问题。
代码:
public class LazySingleton {
private static LazySingleton lazySingleton;
//申明私有的构造方法,无法外部通过new初始化对象
private LazySingleton() {
}
public static LazySingleton getLazySingleton() {
//多线程中,可能出现问题,导致多次初始化
if (lazySingleton == null) {
System.out.println("完成懒汉加载");
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
在多线程中,一个线程准备创建一个对象,这时另一个线程进入if条件判断中,此时对象还未创建,两个线程都将创建对象。
懒汉—Version2.0
public class LazySingleton {
private static LazySingleton lazySingleton;
//申明私有的构造方法,无法外部通过new初始化对象
private LazySingleton() {
}
//同步
public static synchronized LazySingleton getLazySingleton() {
if (lazySingleton == null) {
System.out.println("完成懒汉加载");
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
一整个方法加上synchronized 进行同步,对性能而言会存在很大的问题,再进一步改进。
懒汉—Version3.0
public class LazySingleton {
/*
* 使用修饰volatile
* 1、在内存的语义上,volatile具有内存的可见性,比如一个volatile修改后,将该变量刷回主存中,
* 能使其他持有该变量的缓存失效,这样就能确保变量是最新的。
* 2、volatile能防止指令重排序
*/
private static volatile LazySingleton lazySingleton;
//申明私有的构造方法,无法外部通过new初始化对象
private LazySingleton() {
}
//同步
public static synchronized LazySingleton getLazySingleton() {
if (lazySingleton == null) {
synchronized (LazySingleton.class) {
if (lazySingleton == null) {
System.out.println("完成懒汉加载");
//不使用volatile修饰,可能会存在lazySingleton指向一个未初始化的对象造成空指针异常
lazySingleton = new LazySingleton();
}
}
}
return lazySingleton;
}
}