什么情况下使用单例模式:
1)控制资源的使用,通过线程同步来控制资源的并发访问;
2)控制实例产生的数量,达到节约资源的目的;
3)作为通信媒体使用,也就是数据共享,在可以在不建立直接关联的情 况下,让多个不相关的两个线程或者进程进行实现通信;
什么环境下使用到单例设计模式:
1)数据库连接池设计
*可以屏蔽不同数据库之间差异
*实现系统对数据库的低度耦合
*被多个系统同时使用
*方便对数据库的连接进行管理
2)打印机
*如果每台计算机装上多台打印机的话, 如果我们每一个线程或者进程都进行独立的打印的话,会出现打印的结果数,打印任务的一部分会包含打印任务的另一部分;
需要一个单例模式的假脱机服务Printer Spooler;
3)三大框架(struts/hibernate/spring)
使用单例模式最核心的一句话:体现出面向对象封装特性中的单一职责和对象自我管理
接下来我们学习一下简单的单例模式:
单例模式(懒汉式):
设计思路:
1.懒汉式虽然解决了内存问题,但是同时也出现了线程问题,相对来说,更多的是使用饿汗式设计模式
1)从用户体验来说,我们应该首选饿汗式模式,我们愿意等待某个程序花较长的时间来初始化,却不喜欢在程序运行时等待太久,给人一中国迟钝的感觉;
代码解释:
public class Singleton {
区别就是在这里:懒汉式是类加载的时候,没有去创建实例,而是等到用的是,就会 去创建
public class Singleton {
private static Singleton singleton = null;
//不要外部人员直接new 专业名称 私有构造方法
private Singleton(){
}
//添加方法
public void add(){
System.out.println("添加成功");
}
public static Singleton getInstance(){
if(singleton==null){
singleton = new Singleton();
}
return singleton;
}
}
单例模式(饿汗式)
设计思路:
1.没有线程问题;在类创建的同时,就已经创建一个静态的对象供系统使用,以后不在改变不过会存在一点小小的内存问题;
代码解释:
public class Singleton {
当这个类被加载的时候,就会被创建一个唯一的实例,因为是static
private static Singleton instance=new Singleton();
将构造器私有化;就是不让外界进行new行为
}
public void save(){
}
提供一个全局发访问点
public static Singleton getInstance(){
return instance;
}
}
getInstance()方法中添加了synchronized关键字,使其变成一个同步方法,目的是为了在多线程环境下保证单例对象唯一。
优点: 只有在使用时才会实例化单例,一定程度上节约了资源。
缺点: 第一次加载时要立即实例化,反应稍慢。每次调用getInstance()方法都会进行同步,这样会消耗不必要的资源。这种模式一般不建议使用。
单例模式(双重检查):
设计思想:
1.DCL模式是使用最多的单例模式实现方式,除非代码在并发场景比较复杂或者JDK 6以下版本使用,否则,这种方式基本都能满足需求;
代码分析:
public class Singleton {
//JDK1.5之后,关键字volatile防止重排序
private static Singleton instance = null;
//私有化构造器 防止外部进行直接调用
private Singleton() {
}
//提供一个全局访问
public static Singleton getInstance() {
// 两层判空,第一层是为了避免不必要的同步
// 第二层是为了在null的情况下创建实例
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
优点: 资源利用率高,既能够在需要的时候才初始化实例,又能保证线程安全,同时调用getInstance()方法不进行同步锁,效率高。
缺点: 第一次加载时稍慢,由于Java内存模型的原因偶尔会失败。在高并发环境下也有一定的缺陷,虽然发生概率很小。
总结:
只要我们学会了这三种单例设计模式基本上就够了,以上都是本人研究的心得体会跟大伙们分享,如有出错,请反馈!