单例(Singleton)模式
单例模式,是指一个类有且仅有一个实例,并且提供一个全局访问点。
应用场景
创建代表单一资源、或单一职责、或高度复用的类对象
场景A:构建只有一个打印机的类 , 那么类Printer就需要设计为单例
场景B: 有客户端和服务端 ,客户端在处理事件a过程中 ,发现与服务端连接不通,于是暂停事件a,去执行事件b,同时新建一个心跳线程Thread_connection,去监控与
服务端的网络通信是否恢复,当恢复的时候,再继续执行事件a 。 然而,处理事件b的时候,也发现与服务端连接不同,这时候也需要创建个心跳线程,待监控网络恢复的时候继
续执行事件b 。 这个时候 ,心跳线程很明显只需要一个就足够 。那么,这个心跳线程Thread_connection 就需要设计为单例了 。
场景C: 工厂类Factory,例如log4j的工厂类,很明显只需要一个担当此职责的实例,于是就选择单例
场景D:Spring工程中,具有高度复用的Service、Dao类,也选择单例模式
使用方式
懒汉式 : 只有在使用的时候才创建对象,似乎有点懒 。 未加锁,非线程安全
package designers.singleton;
/**
* 懒汉式:只是在需要的时候才创建对象
* @author xubo
*
*/
public class Slacker {
/**
* 私有构造函数
*/
private Slacker() {
}
private static Slacker instance = null;
public static Slacker getInstance() {
if (instance == null) {
instance = new Slacker();
}
return instance;
}
}
饿汉式 :类初始化的时候就创建了对象 ,似乎很饥饿的样子 。
package designers.singleton;
/**
* 饿汉式:类加载的时候就创建了对象
* @author xubo
*
*/
public class Hungry {
/**
* 私有构造函数
*/
private Hungry() {
}
private static Hungry instance = new Hungry();
public static Hungry getInstance() {
return instance;
}
}
双重锁判定:2次判断对象是否为null,第二次判断的时候加锁,如果2次都为null,那么就创建对象 。 线程安全 ,推荐
package designers.singleton;
/**
* 双重锁判定:判断2次是否为null,才创建对象。且加锁防止并发
* @author xubo
*
*/
public class DoubleCheckAndLock {
private DoubleCheckAndLock() {
}
private static volatile DoubleCheckAndLock instance = null;
public static DoubleCheckAndLock getInstance() {
if (instance == null) {
synchronized (DoubleCheckAndLock.class) {
if (instance == null) {
instance = new DoubleCheckAndLock();
}
}
}
return instance;
}
}
PS : 最后的双重所判定之所以加 volitale关键字,是为了防止new指令的指令重排。
Sping的bean配置中 ,使用的就是第3中方式
<bean id="printWriter" class="cn.con.PrintWriter" scope="singleton">