java 单件_Java设计模式——线程安全的单件模式

单件模式,也称单例模式,用以创建独一无二的、只能有一个实例的对象。

单件模式的类图是所有模式的类图中最简单的——只有一个类。尽管从类设计的视角来看单件模式很简单,但是实现上还是会遇到一些问题,本文着重对这一点来进行分析解决。

最简单的单件模式的实现,代码如下:

1 /*2 Created by McBye King on 2016/10/23.

3 */

4 public class Singleton {

5 private static Singleton singleton;

6 private Singleton(){}

7 public static Singleton getSingleton(){

8 if(singleton == null){

9 singleton = new Singleton();

10 }

11 return singleton;

12 }

13 }

结合以上的代码,对单件模式进行简单的阐述。

单件模式中,利用一个静态变量来记录Singleton类的唯一实例。把构造器声明为私有的,只有自Singleton类内才可以调用构造器。为了实例化这个类,于是调用getSingleton方法,在其中实例化并返回这个实例。这里还有一个“延迟实例化”的思想,在此处,如果我们不需要这个实例,它就永远不会产生。当然在实际中可以给这个类添加其他行为。

看起来这已经是单件模式的全部了,因为单件模式太简单了,但是如果细细追究,还有很多问题。

想一个问题,如果有两个或者更多的线程调用使用上述的单例的类,会怎么样呢?

因为没有对这个单例的类对外的接口getSingleton()方法进行保护,每一个线程都可以同时调用到这个函数,有可能若干个线程同时访问到这个方法,同时进行了if(singleton == null)的判断,因为是同时的,所以大家看到的都是未曾实例化的singleton,于是紧接着就有若干个Singleton实例对象出现——这完全违反了单件模式的本意。——如果你说这也太偶然了吧,确实是的,但是确实实际存在的问题,有很大几率出现重大bug的问题

接下来我们考虑怎么解决这个问题。

1、 只要把getSingleton()变成同步(synchronized)方法 ,多线程灾难几乎就可以解决了,如下示例:

/**

Created by McBye King on 2016/10/23.

*/

public class Singleton {

private static Singleton singleton;

private Singleton(){}

public static synchronized Singleton getSingleton(){

if(singleton == null){

singleton = new Singleton();

}

return singleton;

}

}

通过添加synchronized关键字到getSingleton()方法中,我们迫使每个线程在进入这个方法之前,要先等候别的线程离开该方法。也就是说不允许两个线程可以同时进入这个方法。

2、 添加synchronized方法无疑可以解决同步问题 ,但是很明显会降低性能,这又导致了另一个问题。如果可以牺牲性能,也即getSingleton()方法的性能对应用程序影响不大的时候,就用上面的方法没有错。否则,就把“延迟实例化”变成“急切”创建实例把。

/**

Created by McBye King on 2016/10/23.

*/

public class Singleton {

private static Singleton singleton = new Singleton();

private Singleton(){}

public static synchronized Singleton getSingleton(){

return singleton;

}

}

在静态初始化器中创建单件,就保证了线程安全。当然了,这种办法适用于应用程序总是创建并使用单件实例,或者在创建和运行时方面的负担不会太重。

3、相对更好一点的办法是: 用“双重检查加锁”,在getSingleton()中减少使用同步 。

来看看代码:

/**

Created by McBye King on 2016/10/23.

*/

public class Singleton {

private volatile static Singleton singleton;

private Singleton(){}

public static Singleton getSingleton(){

if(singleton == null){

synchronized (Singleton.class){

if(singleton == null){

singleton = new Singleton();

}

}

}

return singleton;

}

}

在上述代码的getSingleton()实例化方法中,先检查实例,如果不存在,就进入同步区块;且只有第一次才会彻底执行同步区块中的代码。

其中的volatile关键字确保:当singleton变量被初始化成Singleton实例时,多个线程正确地处理singleton变量。

如果性能是考虑的重点的话,上述办法可以帮助大大减少getSingleton()的时间耗费。——前提是在Java 5以及之后的Java版本中。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值