设计模式--单例模式(三)改进型懒汉式
发表于2012/8/30 12:07:29 4078人阅读
分类: JAVA研修 读书笔记 设计模式
由此想要很简单的实现线程安全,可以采用静态初始化器的方式,他可以由JVM来保证线程的安全性。比如第一节的饿汉式实现方式。但是这样一来,会浪费一定的空间,因为这种实现方式,会在类装载的时候就初始化对象,不管你需不需要。
如果现在有一种方法能够让类装载的时候不会初始化对象,不就解决问题了?一种客卿的方式就是采用类级内部类,在这个累计内部类里面去创建对象实例。这样一来,只要不适用这个类级内部类,那就不会创建对象实例。从而同时实现延迟加载和线程安全。
来看一下代码:
/**
* 懒汉式单例模式改进
* 实现延迟加载,缓存
* Lazy initialization holder class
* 这个模式综合运用了java的类级内部类和多线程缺省同步锁的知识
* @author qian.xu
*
*/
public class MySingleton2a {
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
* 没有绑定的关系,而且只有被调用到才会装载,从而实现了延迟加载
* @author qian.xu
*
*/
private static class Singleton{
/**
* 静态初始化器,用JVM来保证线程安全
*/
private static MySingleton2a singleton = new MySingleton2a();
static {
System.out.println("---->类级的内部类被加载");
}
private Singleton(){
System.out.println("---->类级的内部类构造函数被调用");
}
}
//私有化构造函数
private MySingleton2a(){
System.out.println("-->开始调用构造函数");
}
//开放一个公有方法,判断是否已经存在实例,有返回,没有新建一个在返回
public static MySingleton2a getInstance(){
System.out.println("-->开始调用公有方法返回实例");
MySingleton2a s1 = null;
s1 = Singleton.singleton;
System.out.println("-->返回单例");
return s1;
}
}
然后是客户端代码:
/**
* 懒汉式单例模式改进
* 实现了延迟加载
* MySingleton2
*/
public static void myprint2a(){
System.out.println("---------------懒汉式单例模式改进--------------");
System.out.println("第一次取得实例(改进懒汉式)");
MySingleton2a s1 = MySingleton2a.getInstance();
System.out.println("第二次取得实例(改进懒汉式)");
MySingleton2a s2 = MySingleton2a.getInstance();
if(s1==s2){
System.out.println(">>>>>s1,s2为同一实例(改进懒汉式)<<<<<");
}
System.out.println();
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//懒汉式
//myprint();
//饿汉式
//myprint2();
//懒汉式改进
myprint2a();
//登记式
//myprint3();
}
输出结果为:
---------------懒汉式单例模式改进--------------
第一次取得实例(改进懒汉式)
-->开始调用公有方法返回实例
-->开始调用构造函数
---->类级的内部类被加载
-->返回单例
第二次取得实例(改进懒汉式)
-->开始调用公有方法返回实例
-->返回单例
>>>>>s1,s2为同一实例(改进懒汉式)<<<<<
根据打印结果我们看出,内部类被加载的时间在外部类调用构造函数后。也就是说,第一次装载外部类的时候,内部类没有被加载,一直到我们调用s1 = Singleton.singleton时,内部类才被加载(延迟加载),又因为他是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证他的线程安全性。
这个解决方案的优势在于:getInstance方法并没有被同步,并且只是执行的一个域的访问,因此延迟初始化并没有增加任何访问成本~