- Published on
设计模式-单例模式
- Authors
- Name
- ReLive27
单例模式
单例模式是设计模式中比较简单的模式,也是很常用的模式,其定义如下:
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
通用类图如下:
通过私有化构造函数确保在一个应用中只有一个实例,并提供静态方法发布对象。
单例模式通用代码(也被称为饿汉式):
public class Singleton {
private static final Singleton singleton= new Singleton();
//限制多个对象
private Singleton (){}
//通过该方法获得实例对象
public static Singleton getSingleton() {
return singleton;
}
//在类中其他方法,尽量是static
public static void doSomething(){
...
}
}
单例模式的优点
- 减少内存开支,特别是一个对象频繁的创建和销毁时。
- 减少系统性能开销,当一个对象的产生需要比较多的资源时,可以通过启动时产生一个单例对象。
- 单例模式可以避免对资产的多重占用。
- 单例模式可以在系统设置全局的访问点,优化和共享资源访问。
单例模式的缺点
- 单例模式对测试不利,在并行开发中,如果单例模式没有完成,是不能进行测试的,因为没有接口也不能mock的方式虚拟一个对象
- 单例模式与单一职责原则有冲突,一个类应该只实现一个逻辑,单例模式把“要单例”和业务逻辑合在一个类中
单例模式使用场景
系统中要求一个类只有一个对象,当存在多个对象时会产生错误影响,可以使用单例模式。
- 要求生成唯一序列号的环境
- 在项目中需要一个共享访问点和共享数据
- 创建一个对象需要消耗很多资源。
- 需要定义大量的静态常量和静态方法(如工具类)
单例模式的注意事项
在高并发情况下,单例模式存在线程同步问题,如下面的一种单例模式实现方式(也称为懒汉式):
public class Singleton {
private static Singleton singleton = null;
//限制产生多个对象
private Singleton(){}
public static Singleton getSingleton() {
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
在并发量增加时可能会出现多个实例,如一个线程A执行到singleton = new Singleton(),但是还没有获得对象,第二个线程B也在执行,执行到singleton == null判断,判断条件为真,于是运行下去也创建了一个对象。
解决线程不安全问题方法有很多,一使用饿汉式的实现方式,静态变量在类加载时初始化,类加载过程是线程安全的,所以饿汉式没有线程安全问题;二是使用Java的锁机制,以下代码示例单例模式(懒汉式)的双重检锁机制:
public class Singleton {
private static volatile Singleton singleton = null;
//限制产生多个对象
private Singleton(){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
总之单例模式比较简单而且应用非常广泛,在Spring框架中每个Bean默认就是单例的。
结论
与往常一样,本文中使用的源代码可在 GitHub 上获得。