单例模式之Lazy Initialization Holder Class模式
1.0 前面已经介绍过两种单例模式:饿汉式单例模式和懒汉式单例模式1.1本文的源码获取:点击下载(建议使用电脑下载,解压缩后将文件夹放入src即可)
1.2代码场景:
A、package内有AppConfig.properties文件。
B、通过获取单例的AppConfigWithLazyClassSingleton对象来读取AppConfig.properties的parameterA和parameterB的值。
1.3代码解读:
1.3.1 AppConfig.properties文件
AppConfig.properties包含两个参数parameterA,parameterB,代码如下:
parameterA=A
parameterB=B
1.3.2 AppConfigWithLazyClassSingleton.java文件
/**代码如下*/
package singlethon_lazyinnerclass;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* 读取应用配置文件(Java静态内部类方式 Lazy Initialization Holder Class 方式)
* @author YJ
*/
public class AppConfigWithLazyClassSingleton {
/**参数A*/
private String parameterA;
/**参数B*/
private String parameterB;
/**类级内部类,也就是静态的成员内部类,该内部类的实例与外部类的实例没有绑定关系,
* 而且只有调用的时候才会装载,从而实现了延迟加载
*/
private static class AppconfigInstanceHolder{
private static AppConfigWithLazyClassSingleton appConfigWithEagerSingleton=new AppConfigWithLazyClassSingleton();
}
/**要点二:私有化构造器*/
private AppConfigWithLazyClassSingleton() {
readConfig();
}
/**要点三:返回静态内部类的单例*/
public static AppConfigWithLazyClassSingleton getInstance(){
return AppconfigInstanceHolder.appConfigWithEagerSingleton;
}
/**读取配置文件*/
private void readConfig(){
Properties properties=new Properties();
//加载当前package下的的AppConfig.properties
InputStream is=AppConfigWithLazyClassSingleton.class.getResourceAsStream("AppConfig.properties");
try {
properties.load(is);
parameterA=properties.getProperty("parameterA");
parameterB=properties.getProperty("parameterB");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {//释放资源
if(is!=null){
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public String getParameterA() {
return parameterA;
}
public String getParameterB() {
return parameterB;
}
}
流程解读(重点):
a、创建一个private 的 static的内部类AppconfigInstanceHolder ,该静态内部类中含有一个静态的单例对象appConfigWithEagerSingleton,并且已经实例化
b、私有化构造器
c、静态方法getInstance()返回静态内部类AppconfigInstanceHolder中的单例对象。
1.4 客户端AppConfigWithLazyClassSingletonMain.java文件
代码如下:
/**代码如下*/
package singlethon_lazyinnerclass;
/***
* 读取应用配置文件(Java静态内部类方式 Lazy Initialization Holder Class 方式) 客户端
* @author YJ
*/
public class AppConfigWithLazyClassSingletonMain {
public static void main(String[] args) {
//通过静态方法getInstance()获取单例对象
AppConfigWithLazyClassSingleton appConfigWithEagerSingleton=AppConfigWithLazyClassSingleton.getInstance();
//获取参数A和参数B
String parameterA=appConfigWithEagerSingleton.getParameterA();
String parameterB=appConfigWithEagerSingleton.getParameterB();
//打印参数A和参数B
System.out.println(parameterA);
System.out.println(parameterB);
}
}
流程解读:
a、通过获取AppConfigWithLazyClassSingleton类的getInstance()获取AppConfigWithLazyClassSingleton对象。
b、通过AppConfigWithLazyClassSingleton对象获取parameterA、parameterA两个参数的值。
c、打印parameterA、parameterB的值。
1.5为什么使用Lazy Initialization Holder Class模式的单例模式,原因如下:
1.5.1饿汉式单例模式的缺点:
无法控制单例对象的创建时间。
(无法保证单例对象是在getInstance()方法的时候被创建)
原因:在Java中static字段初始化的时间为当该类被触及时所有静态字段将会被初始化,所以饿汉式单例模式是无法保证单例对象是在调用getInstance()的时候被创建。
举例:如果单例类Singlethon中有一个单例对象
public static Singlethon singlethon=new Singlethon();
同时还有一个public 的 静态变量 number
public static int number=0;
当外界调用Singlethon.number时,单例对象singlethon将会被加载。所以singlethon对象无法保证是在调用getInstance()的时候被创建。
1.5.2 Lazy Initialization Holder Class模式可以解决这个问题。