单例模式,顾名思义就是一个类只产生一个实例。
1.为什么要使用单例模式
原因有很多,这篇文章写的很详细http://www.cnblogs.com/seesea125/archive/2012/04/05/2433463.html
但是主要是为了省去频繁创建、销毁的资源消耗。比如一个web应用,需要连接到数据库,如果对于数据库连接池不做单例模式,那么每次请求我们都要建立一个连接池,每个连接池都建立maxConnections个数据库连接,这是非常消耗资源的,但是通过单例模式,我们只在项目启动或者第一次请求的时候建立好连接池,并实例化好数据库链接,调用完之后并不去销毁它,下一次调用的时候,直接 getInstance() 就省去了创建和销毁对于内存、时间的消耗。
2.先上一波类图
3. 单例模式的实现
单例模式的实现1.(懒汉模式):
public class Emperor {
private static final Emperor emperor =new Emperor(); //懒汉模式,在类初始化的时候,直接把创建对象
private Emperor(){
//构造方法声明为private,让外部类无法 new 对象
}
//返回创建的实例
public static Emperor getInstance(){
return emperor;
}
//(类中的方法,尽量是 static 的)
public static void say(){
System.out.println("我就是皇帝某某某....");
}
}
单例模式的实现2.(饿汉模式):
public class Emperor2 {
private static Emperor2 emperor2 = null; //初始化一个皇帝
private Emperor2(){
//世俗和道德约束你,目的就是不希望产生第二个皇帝
}
/**
* 注意,这种双检查机制锁在逻辑上是完美的,但是实际上并不能保证单例模式,
* 因为Java内存模型的无序写入特性
* @return
*/
public static Emperor2 getInstance(){
if(emperor2 == null){
synchronized (Emperor2.class){
if(emperor2 == null){
emperor2 = new Emperor2();
}
}
}
return emperor2;
}
//皇帝发话了(类中的方法,尽量是 static 的)
public static void say(){
System.out.println("我就是皇帝某某某....");
}
}
main方法调用,以懒汉模式为例:
/**
* 单例模式
*/
public class Main {
public static void main(String[] args) {
Emperor instance = Emperor.getInstance();
System.out.println(instance.hashCode());
Emperor instance2 = Emperor.getInstance();
System.out.println(instance2.hashCode());
//输出的两个hashcode是相同的,说明这是同一个对象
}
}
4. 关于这两种实现的区别
懒汉模式:在类初始化时就实例化对象,在调用时直接返回
饿汉模式:在第一次调用的时候实例化,之后直接返回。注意:本文中的实现是“双重检查锁机制”的写法,这样既能保证效率(避免每次调用方法时synchronized的开销),又能保证多线程情况下的同步。这种方法在逻辑上是完美的,但是其实还是有可能会实例化多个对象出来,原因可参考这篇文章,
http://blog.csdn.net/chenchaofuck1/article/details/51702129
我是看不太懂(我太菜了),所以还是推荐使用懒汉模式,方便,而且没什么明显的缺点。
5.单例模式会被GC回收吗
这个问题比较难,但是有一个博主做了个试验(他的观点是不会),仅供参考http://blog.csdn.net/zhengzhb/article/details/7331354