单例模式的使用场景,
- 想确保任何情况下都绝对只有一个实例
- 在程序上表现出只存在一个实例
依据上面的使用场景,得出单例模式的构建,
- 只有一个实例
- 该实例对象由该类本身创建
- 提供全局访问点能够对该实例对象进行获取
1.代码实现
单例模式的主要角色是单例类,该类中通常包含如下实现,
- 私有的构造方法
- 私有的类成员变量
- 公有的类实例对象访问方法
懒汉式实现
- 懒汉式的实现一定注意线程安全
public class Singleton{
// 使用类变量缓存创建的实例, volatile保证该对象线程同步
private static volatile Singleton instance = null;
private Singleton() {}
// 使用同步的形式保证线程安全
public static synchronized Singleton getInstance() {
if (instance == null)
instance = new Singleton();
return instance;
}
}
- 测试懒汉式
public class Main{
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2); // true
}
}
懒汉式的特点是,类加载时没有创建实例,而是在调用 getInstance 方法时才去创建单例,所以就会存在线程安全性问题。但是每次访问都有同步问题,消耗资源,影响性能。
所以建议使用饿汉式。
饿汉式实现
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
饿汉式就比较好理解,直接在类创建的同时就生成静态成员变量供外部使用,即预先加载法,所以不存在线程安全性问题。
2.单例模式优缺点
- 单例模式一般难以拓展,一旦拓展基本上一定会对代码进行修改
- 单例模式与单一职责原则冲突。一个类,通常只关心它要实现的业务逻辑,但是单例模式既要关心自己是否单例,又要实现业务逻辑,融合性比较高。
3.单例模式使用场景
单例模式只有一个实例,常见的使用场景有,
- 要求生成唯一序列号的环境
- 网站计数器,采取单例模式有助于同步
- 文件系统、打印机、资源管理器等,因为底层资源只能同时被一方操纵,所以这些模块暴露的接口必然是单例的
- Java 中的 dao、service 一般都是单例的,而 action 层一般都是多例。