您的位置:首页 > 其它

单例模式,多例模式及其应用

2015-05-26 15:16 211 查看
单例模式:

当整个应用只允许出现一个类实例时,我们经常用到单例模式。比如工具类,国际化服务提供类等等

单例模式分为两种,一种饿汉式:在类加载的时候即完成对象创建,保证始终只有一个对象存在

[java] view
plaincopy

Class Singleton{

private static Singleton s = new Singleton ();

private Singleton(){}

public static Singleton getInstance(){

return s;

}

}

一种懒汉式,在需要时创建对象,需要注意线程安全

[java] view
plaincopy

Class Singleton{

private static Singleton s;

private Singleton(){

}

public static Singleton getInstance(){

if(s==null){

synchronized(Singleton.class){//1

if(s==null){ //2

s = new Singleton(); //3

}

}

}

return s;

}

}

以上为什么要判断两次s==null呢(双重检查机制)?

线程 1 进入
getInstance()
方法。
由于
instance
null
,线程 1 在 //1 处进入
synchronized
块。
线程 1 被线程 2 预占。
线程 2 进入
getInstance()
方法。
由于
instance
仍旧为
null
,线程 2 试图获取 //1 处的锁。然而,由于线程 1 持有该锁,线程 2 在 //1 处阻塞。
线程 2 被线程 1 预占。
线程 1 执行,由于在 //2 处实例仍旧为
null
,线程 1 还创建一个
Singleton
对象并将其引用赋值给
instance

线程 1 退出
synchronized
块并从
getInstance()
方法返回实例。
线程 1 被线程 2 预占。
线程 2 获取 //1 处的锁并检查
instance
是否为
null

由于
instance
是非
null
的,并没有创建第二个
Singleton
对象,由线程 1 创建的对象被返回。

请注意,看起来好像双重检查锁定背后的理论是完美的。不幸地是,现实完全不同。双重检查锁定的问题是:并不能保证它会在单处理器或多处理器计算机上顺利运行。

双重检查锁定失败的问题并不归咎于 JVM 中的实现 bug,而是归咎于 Java 平台内存模型。内存模型允许所谓的“无序写入”,这也是这些习语失败的一个主要原因。

鉴于此,笔者个人偏向于采用饿汉式创建方式。

多例模式:

多例模式应用场景举例:

多并发请求环境下,系统需要为每个客户端的独立请求提供单独服务的资源,但是系统总的开销是有限的,系统在并发量很大时也不可能为所有的并发请求同时提供相应的资源,否则不但系统资源消耗量大而且非常耗时。这时就可以考虑使用池的概念,也即是一种多例模式的实现。具体的应用场景,比如数据库连接池、EJB无状态会话Bean的实例池

代码实现上一般是提供一个容器类,也即是容纳资源对象的池,对象池的一些属性可以通过配置文件来配置,比如数据库连接池中容纳的Connection类型的对象数目的上限和下限、闲置连接超时时间等;然后每当应用程序请求数据库连接时,先判断池中有无空闲的连接,如有,即返回这个对象,如没有,则新建一个连接对象,并放入连接池中进行管理
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: