2 单例模式(Singleton Pattern)
2.1 为什么需要单例模式?什么是单例模式
对于系统中的某些类,只有一个实例十分重要。那么如何保证一个类在系统中只有一个实例并且使这个实例易于被访问呐?更好的解决办法是让类自身负责保存它的唯一实例
。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机
。
单例模式
(又名单件模式/单态模式):单例模式确保某一个类只有一个实例,而且自行实例化
并向整个系统提供这个实例
,这个类称为单例类,它提供全局访问的方法
。是一种对象创建型模式。
单例模式的三个要点:
①某个类只有能一个实例;
②必须自行创建这个实例;
③必须自行向整个系统提供这个实例。
2.2 结构与角色
仅包含一个单例角色。需要根据单例模式的三个要点去实现单例模式,因而也产生了两种不一样的方式去实现单例模式。
2.3 单例模式的实现
package Singleon;
/*
方式一:
借用静态内部类来实现懒加载
支持多线程
*/
public class Singleon04 {
private Singleon04(){};
//公有的方法访问
public static Singleon04 getInstance(){
return InnerClass.s;
}
private static class InnerClass{
static Singleon04 s = new Singleon04();
}
}
package Singleon;
/*
方式一:饿汉式
特点:简单
缺点:类加载时就创建了对象,浪费内存----不支持懒加载
类的加载早于线程 支持多线程
*/
public class Singleon01 {
//不想在别的地方被初始化需要显示的写出来构造函数,并且私有化
private static Singleon01 s = new Singleon01();
private Singleon01(){};
//公有的方法访问
public static Singleon01 getInstance(){
return s;
}
}
package Singleon;
/*
方法二:需要的时候再创建 懒汉式
节省了内存,借助同步方法,保持多线程下的单例
缺点:效率降低
*/
public class Singleon02 {
private static Singleon02 s;
private Singleon02(){};
//公有的方法访问
public synchronized static Singleon02 getInstance(){
if(s == null){
s = new Singleon02();
}
return s;
}
}
package Singleon;
/*
方式二:同步代码块 ,来保证多线程下的单例
双检式
懒加载
节省内存
*/
public class Singleon03 {
private static Singleon03 s;
private Singleon03(){};
//公有的方法访问
public synchronized static Singleon03 getInstance(){
if(s == null){
synchronized (Singleon03.class){
if(s == null){
s = new Singleon03();
}
}
}
return s;
}
}
第一重检查,说明还没有任何一个线程给它赋值,那么就给它加锁,第二重检查的主要目的,就是为了防止多次被初始化, 因为在第一次检查的初始化的时候,其他线程有可能已经对其进行初始化, 第二次检查如果结果依然为null说明,在上面的这段代码执行期间,没有其他线程对它进行初始化。
测试代码:
package Singleon;
public class TestSingleon {
public static void main(String[] args) {
//getInstance()获取唯一一个实例化对象
Singleon01 s1 = Singleon01.getInstance();
Singleon01 s2 = Singleon01.getInstance();
if(s1.hashCode() == s2.hashCode() && s1.equals(s2)){
System.out.println("s1和s2是同一个对象实例");
}else{
System.out.println("s1和s2不是同一个对象实例");
}
//Singleon01 s2 = Singleon01.s; 这样就不行,不能被访问
}
}
/*
结果:
s1和s2是同一个对象实例
*/
2.4 模式分析
饿汉式单例类
在自己被加载时就将自己实例化。资源利用效率上稍微差于懒汉式单例类。速度和反应时间稍好于懒汉式单例类。
懒汉式单例类
在实例化时必须要处理好多个线程同时首次引用此类时的访问限制问题。需要进行同步化机制进行控制
。
优点:
- 提供对唯一实例的受控访问。
- 节约系统资源,对于需要频繁创建和销毁的对象,单例模式可以提高系统的性能。
缺点:
- 该模式没有抽象层,其扩展有很大难度。
- 单例类责任过重,一定程度上违背了“单一职责原则”。
使用环境:
系统只需要一个实例对象。
参考书籍:
《设计模式》
《软件体系结构与设计实用教程》-- 刘其成 毕远伟(中国铁道出版社有限公司)