单例模式
1) 单例的实现:
线程安全(加锁):
上述代码中的一个缺点是该类加载的时候就会直接new 一个静态对象出来,当系统中这样的类较多时,会使得启动速度变慢。现在流行的设计都是讲“延迟加载”,我们可以在第一次使用的时候才初始化第一个该类对象。所以这种适合在小系统。
如果所使用的公用变量在多线程下没有被保护机制时,变量结果会和理论值不一致,这样就叫作线程不安全,相反公用变量在保护机制下工作,就不会出现未知变化,那这样线程就是安全的.
单例中有个部分,就是有个对象作为这个类的成员变量被保存,而不是作为局部变量,所以其他方法发生并发访问这个对象时其实是在操作同一个对象。
举个例子,两个人同时调用一个方法(给我蛋糕),但这个方法返回一个蛋糕的单例对象,两个人同时获得了同一个蛋糕,并坐下,举起刀叉,结果第一个人先吞了蛋糕,就造成了第二个人明明得到了蛋糕,却没能吃到这个结果。
Tomcat可以用单例预热。
传统单例可以节省内存
为了线程安全:(使用同步锁)
单锁与双锁:
上述代码中的一次锁住了一个方法, 这个粒度有点大,改进就是只锁住其中的new语句就OK。就是所谓的“双重锁”机制:
管理上的单例实现:(登记式单例)
本例子中利用Map里面存储创建对象的id来阻止对象重复实例化。
什么时候用单例?无状态的对象都可以作为单例。无数据的类似Service(无id那些),Dao是可以作为单例的,有数据的,如UserBean不可以。(如打印机)。还有类只有只读数据(无set方法)可以作为单例:
还有如下应用情景:
1.Windows的TaskManager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windowstask manager吗?不信你自己试试看哦~
2.windows的RecycleBin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
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