始终如一 -- 单例模式分析总结
定义
顾名思议,单例,单一实例,就是在程序运行期间确保某一个类只有一个实例,一般称其为Singleton类。
实现方法
既然只能有一个实例,那么肯定不能让程序运行期间随时都能new出一个实例,所以将构造函数私有化,通过在类内部自行实例化一个对象,并且通过getInstance()方法,向外部提供这个实例。
通用代码
“饿汉式”单例,即不管之后是否能用的上此实例,在初始化类的时候就实例化对象,显得很“饥饿”
此方法线程安全
public class Singleton { private static final Singleton singleton = new Singleton(); private Singleton(){}; //通过此方法获取唯一实例 public static Singleton getSingleton() { return singleton; } //类中其他方法 public static void doSomething() { } }
“懒汉式”单例,在最开始不实例化对象,到后期运行需要时再实例化并返回,显得很“懒”
为了实现懒汉式的线程安全,需要加锁
public class Singleton { private static Singleton singleton = null; private Singleton(){}; //通过此方法获取唯一实例
//如果是单线程,不需要加锁,多线程则需要
public static synchronized Singleton getSingleton() { if (singleton == null) { singleton = new Singleton(); } return singleton; } //类中其他方法 public static void doSomething() { } }
为什么需要加锁?
在高并发的情况下,假如线程A执行到了singleton = new Singleton(),但是因为对象还在初始化,所以还没有获取对象,在此期间,线程B执行到singleton == null,此时判定为真,那么线程B也会去实例化对象,造成内存中出现了两个实例,所以多线程情况下需要加锁。
优缺点
优点
1. 减少内存开支
2.减少系统性能开销
3.避免对资源的多重占用
4.优化和资源共享访问
缺点
1.一般没有接口,扩展困难
2.对测试不友好,在并行开发中,如果单例模式没有完成,不能进行测试
3.与单一职责原则冲突,单例模式“单例”和业务逻辑融合在了一个类中
使用场景
1.要求生成唯一序列号的环境
2.整个项目共享的访问点或者数据
3.需要定义大量的静态变量和静态方法的环境,此时也可以直接声明为static