码迷,mamicode.com
首页 > 其他好文 > 详细

单例模式

时间:2015-04-14 08:31:19      阅读:152      评论:0      收藏:0      [点我收藏+]

标签:设计模式   线程池   单例   饿汉式   线程安全   

 单例模式

技术分享

1) 单例的实现:

线程安全(加锁):

上述代码中的一个缺点是该类加载的时候就会直接new 一个静态对象出来,当系统中这样的类较多时,会使得启动速度变慢。现在流行的设计都是讲“延迟加载”,我们可以在第一次使用的时候才初始化第一个该类对象。所以这种适合在小系统。

如果所使用的公用变量在多线程下没有被保护机制时,变量结果会和理论值不一致,这样就叫作线程不安全,相反公用变量在保护机制下工作,就不会出现未知变化,那这样线程就是安全的.

单例中有个部分,就是有个对象作为这个类的成员变量被保存,而不是作为局部变量,所以其他方法发生并发访问这个对象时其实是在操作同一个对象。

举个例子,两个人同时调用一个方法(给我蛋糕),但这个方法返回一个蛋糕的单例对象,两个人同时获得了同一个蛋糕,并坐下,举起刀叉,结果第一个人先吞了蛋糕,就造成了第二个人明明得到了蛋糕,却没能吃到这个结果。

Tomcat可以用单例预热。

传统单例可以节省内存

技术分享

为了线程安全:(使用同步锁)

技术分享

单锁与双锁:

技术分享

上述代码中的一次锁住了一个方法, 这个粒度有点大,改进就是只锁住其中的new语句就OK。就是所谓的“双重锁”机制:

技术分享

管理上的单例实现:(登记式单例)

技术分享

本例子中利用Map里面存储创建对象的id来阻止对象重复实例化。

什么时候用单例?无状态的对象都可以作为单例。无数据的类似Service(无id那些),Dao是可以作为单例的,有数据的,如UserBean不可以。(如打印机)。还有类只有只读数据(无set方法)可以作为单例:

技术分享

还有如下应用情景:

1.WindowsTaskManager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windowstask manager吗?不信你自己试试看哦

2.windowsRecycleBin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。

3. 网站的计数器,一般也是采用单例模式实现,否则难以同步。

4. 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。

5. Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。

6. 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。

7. 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。

8. 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。

9. HttpApplication也是单位例的典型应用。熟悉ASP.Net(IIS)的整个请求生命周期的人应该知道HttpApplication也是单例模式,所有的HttpModule都共享一个HttpApplication实例.

10.说到门面类,就不能不提门面(Facade)模式。客户端与多个子系统的通信必须通过一个统一的门面(Facade)对象进行,这就是门面模式。这个统一的门面(Facade)对象就是门面类。在门面模式中,通常只需要一个门面类,并且此门面类只有一个实例,换言之它是一个单例类。但这不是绝对的。

写单例时通用的规则:

1.       使类变成单例必须用static存放常量池。

一般在方法内定义:

是线程安全的,变量在栈中有个引用指向堆里的对象。

而向管理上的单例:

Map放在常量池在堆中,可以为多个线程访问,线程不安全。

Servlet是单例的,在Servlet里面用privateString name;之类会因为do/get方法引发线程安全问题。第三方类库要了解api可不可以做成单例。(有方法修改数据就不可作为单例)

单例模式也是一种比较常见的设计模式,它到底能带给我们什么好处呢?其实无非是三个方面的作用:

第一、控制资源的使用,通过线程同步来控制资源的并发访问;

第二、控制实例产生的数量,达到节约资源的目的。

第三、作为通信媒介使用,也就是数据共享,它可以在不建立直接关联的条件下,让多个不相关的两个线程或者进程之间实现通信。

比如,数据库连接池的设计一般采用单例模式,数据库连接是一种数据库资源

两种单例:

1. 饿汉式

public class EagerSingleton

{

private static final EagerSingleton m_instance = newEagerSingleton();

/**

* 私有的默认构造子

*/

private EagerSingleton() { }

/**

* 静态工厂方法

*/

public static EagerSingleton getInstance()

{

return m_instance;

}

}

2. 懒汉式

public class LazySingleton

{

private static LazySingleton m_instance = null;

/**

* 私有的默认构造子,保证外界无法直接实例化

*/

private LazySingleton() { }

/**

* 静态工厂方法,返还此类的惟一实例

*/

synchronized public static LazySingleton getInstance()

{

if(m_instance == null)

{

m_instance = newLazySingleton();

}

return m_instance;

}

}

饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变

懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的

推荐使用第一种

单例模式

标签:设计模式   线程池   单例   饿汉式   线程安全   

原文地址:http://blog.csdn.net/wws199304/article/details/45035131

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!