设计模式之(三)——单例模式

单例模式:
根据单例模式的设计思想,就是想保证类只有一个实例即只有一个对象。而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源等。
一般出现的场景是:
1、资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如记录系统日志文件,共享配置文件的读取。
2、控制资源的情况下,方便资源之间的互相通信。如线程池,数据库连接池等。
实现方法很多种:
1、饿汉式:
public class SingletonTest {  
    private static SingletonTest instance = new SingletonTest();  
    //私有构造方法  只能通过 公有方法 getInstance 获得实例
    private SingletonTest(){}  
    public static SingletonTest getInstance() {  
        return instance;  
    }  
}  

饿汉式在类加载时静态变量 instance 就进行初始化。资源利用率不好。

2、懒汉式:

public class SingletonTest {  
    private static SingletonTest instance = null;  
    private SingletonTest(){}  
    //synchronized 保证线程同步,线程安全
    public static synchronized SingletonTest getInstance() {  
        if (instance == null) {  
            instance = new SingletonTest();  
        }  
        return instance;  
    }  
}  

懒汉式线程安全,在类加载时并不进行初始化,只是在调用方法getInseance() 时会进行初始化,实现了延迟加载(lazy load)。但是也就是因为只要调用 getInstance() 就会都需要进行 线程锁定判断,进行初始化资源,降低系统的性能,特别是多线程,高并发的状态下。

3、双重校验索锁定(懒汉式的改进):
双重校验是懒汉式的改进,因为当同时有2个进程a,b 调用getInstance(),当a进入 线程锁定,创建对象,b只能等a 执行完,退出来,才能进入进程同步块。但是还是不知道 a 创建对象没有。可能就会出现创建了2个对象。

public class SingletonTest {
    //被volatile修饰的成员变量可以确保多个线程都能够正确处理  
    private volatile static SingletonTest instance = null;  
    private SingletonTest(){}  
    public static synchronized SingletonTest getInstance() {  
       if (instance == null) { //第一次校验 
           synchronized (SingletonTest.class) {  
               if (instance == null) {  //第二次校验
                   instance = new SingletonTest();  
               }  
           }  
        } 
    } 
}  

这样还是有一个问题,就是使用volatile,由于volatile关键字会屏蔽Java虚拟机所做的一些代码的优化,可能会降低系统运行的效率。

4、静态内部类:
静态内部类是一个更好的实现方式,通过内部类创建对象,外部类进行返回。

public class SingletonTest {  
    private static class HolderSingleton {  
        private static final SingletonTest INSTANCE = new SingletonTest();  
    }  
    private Singleton (){}  
    public static final SingletonTest getInstance() {  
        return HolderSingleton .INSTANCE;  
    }  
}  

类加载时不会实例化,只有调用 内部类的 getInstance() 才会实例化,由于是静态的实例,所以创建的实例是唯一的,而且是线程安全的。
其实这就是 IoDH (Initialization Demand Holder) 技术。既可以实现延迟加载,又可以保证线程安全,不影响系统性能。

5、单个元素枚举类型:

public enum SingletonTest {  
    INSTANCE;
    private TestObject obj;
    SingletonTest() {
        obj = new TestObject();
    }
    private Singleton getInstance() {
        return obj;
    }  
} 

根据枚举的唯一性,在初始化的时候,构造器就生成obj,根据唯一的instance 去获取obj 也一定是唯一的,这个单例模式实现的很巧妙。

其实这是Joshua Bloch(Effective Java作者)的思路,这种方法更加简洁,无偿提供序列化机制,绝对防止多次序列化,即使面对复杂的序列化或反射攻击的时候。只是这只能是针对 java 1.5 以上版本的。 因为 java 1.5 才有枚举enum 新特性。

用 Joshua 的话说“单元素的枚举类型已成为实现 Singleton 的最佳方法。

共勉。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值