设计模式:单例模式

[b]单例模式[/b]是一个简单的创建者类型的模式,必须保证在系统中最多只能有一个唯一的对象实例,有如下特点:
[b]1、单例类必须保证最多只有一个实例;
2、必须由单例类自己创建唯一的实例;
3、单例类必须给其他所有对象提供其唯一的实例。[/b]
根据创建时间,单例模式又可以分为饥汉式和饱汉式两种,下面通过JAVA代码来分析二者的优缺点。
[b]饥汉式单例模式:[/b]

/**
* HungerySingletonPatternTest
* 饥汉式单例模式
*/
public class HungerySingletonPatternTest{
private static final HungerySingletonPatternTest instance = new HungerySingletonPatternTest();

//构造函数声明为private,不能通过new关键字由外部生成实例对象
private HungerySingletonPatternTest(){
}

//只能通过该方法获取类的实例对象
public static HungerySingletonPatternTest getInstance(){
return instance;
}
}

饥汉式单例模式优点是简单切线程安全,但是缺点也很明显,在类加载时就要初始化单例类的对象,有可能在整个系统的生命周期内都用不到该单例对象,这样就造成了浪费,特别是该单例类的生成和持有要占很大资源的时候。
饱汉式单例模式改掉了饥汉式单例模式的缺点,代码如下:

/**
* FullSingletonPattern
* 饱汉式单例模式
*/
public class FullSingletonPatternTest{
private static final FullSingletonPatternTest instance = null;

//构造函数声明为private,不能通过new关键字由外部生成实例对象
private FullSingletonPatternTest(){
}

//只能通过该方法获取类的实例对象
public static synchronized FullSingletonPatternTest getInstance(){
if(instance == null){
new HungerySingletonPatternTest();
}
return instance;
}
}

饱汉式单例模式虽然改进了饥汉式单例模式的缺点,但是每次在获取单例对象时都要锁(Class Lock),在单线程或没够对单例类对象有竞争的应用场景下,加锁会造成不必要的性能损失。
对于饱汉式单例模式的缺点,有人提出了所谓的“双重检查锁”的饱汉式单例模式,代码如下:

/**
* DoubleCheckerSingletonPatternTest
* “双重检查锁”饱汉式单例模式
*/
public class DoubleCheckerSingletonPatternTest{
private static final DoubleCheckerPatternTest instance = null;

//构造函数声明为private,不能通过new关键字由外部生成实例对象
private DoubleCheckerSingletonPatternTest(){
}

//只能通过该方法获取类的实例对象
public static DoubleCheckerSingletonPatternTest getInstance(){
if(instance == null){
synchronized(DoubleCheckerSingletonPatternTest.class){
if(instance == null){
new DoubleCheckerSingletonPatternTest();
}
}
}
return instance;
}
}

但是“双重检查锁”的饱汉式单例模式,实际上不是线程安全的:由于编译器的优化,允许出现主存和线程工作内存数据不一致问题,这就是“DCL失效”的问题,并不能保证这个双重检查锁定习语有效。它偶尔会失败,而不是总失败。具体原因请参详[url]http://www.ibm.com/developerworks/cn/java/j-dcl.html[/url]。
JAVA语言提供内部静态类,我们可以基于内部静态类的特性,改进饱汉式单例模式,提供一种高效而安全的单例模式,代码如下:

/**
* StaticInnerClassSingletonPatternTest
* 基于内部静态类的单例模式
*/
public class StaticInnerClassSingletonPatternTest{

private StaticInnerClassSingletonPatternTest{}

//定义一个私有的内部静态类并在其中初始化外部单例对象
private static class SingletonHolder{
static final StaticInnerClassSingletonPatternTest INSTANCE = new StaticInnerClassSingletonPatternTest();
}

//只能通过该方法获取类的实例对象
public static StaticInnerClassSingletonPatternTest getInstance(){
return StaticInnerClassSingletonPatternTest.INSTANCE;
}
}

通过静态内部类的方式生成的单例模式,既保证了线程安全的,有保证了延迟加载。
在JDK发展到JDK 5.0之后,volatile + synchronized可以在保证内存模型的三个特性,即可见性、原子性和顺序性之外,对于被定义为volatile的变量,又禁用了volatile变量的重排序优化,就可以通过如下方式生成的单例模式,既保证安全性又兼顾延迟加载的功能,代码如下:

/**
* NewDoubleCheckerSingletonPatternTest
* volatile + synchronized的“双重检查锁”饱汉式单例模式
*/
public class NewDoubleCheckerSingletonPatternTest{
private static volatile NewDoubleCheckerSingletonPatternTest instance = null;

//构造函数声明为private,不能通过new关键字由外部生成实例对象
private NewDoubleCheckerSingletonPatternTest(){
}

//只能通过该方法获取类的实例对象
public static NewDoubleCheckerSingletonPatternTest getInstance(){
if(instance == null){
synchronized(NewDoubleCheckerSingletonPatternTest.class){
if(instance == null){
new DoubleCheckerSingletonPatternTest();
}
}
}
return instance;
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值