单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

单例模式也是开发过程中使用的最多的一种设计模式,它只允许创建一个对象,因此节省内存,加快了对象访问速度,当对象需要被公用的场景就很适合使用单例模式;但是它不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态

需要注意的是:

  1. 单例类只能有一个实例

  2. 单例类必须自己创建自己的唯一实例

  3. 单例类必须给所有其他对象提供这一实例

懒汉模式

顾名思义就是特别懒,在类加载时不初始化,等到第一次被使用时才初始化。

public class Singleton{
// 创建示例,注意此时没有new
private static volatile Singleton instance;
// 构造方法私有化,无法在外部创建实例
private Singleton(){

}
// 公有的静态方法,返回实例对象
public static Singleton getInstance(){
// 判断是否存在实例,没有才实例化
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton()
}
}
}
return instance;
}

}

这种写法用了两个判断,更重要的是它同步的是代码块而非方法,这样效率就会大大提升。

简单的解释一下为什么要用两个if判断:这是为了线程安全考虑,还是那个场景,对象还没实例化,两个线程A和B同时访问静态方法并同时运行到第一个if判断语句,这时线程A先进入同步代码块中实例化对象,结束之后线程B也进入同步代码块,如果没有第二个if判断语句,那么线程B也同样会执行实例化对象的操作了,但此时我们加上了第二个if判断,这样就不会重复执行对象的实例化操作,也就大大提升了代码效率。

饿汉模式

创建对象的时候就直接进行实例化操作

public class Singleton{
// 创建示例,注意此时没有new
private static volatile Singleton instance = new Singleton();
// 构造方法私有化,无法在外部创建实例
private Singleton(){

}
// 公有的静态方法,返回实例对象
public static Singleton getInstance(){
return instance;
}

}

这种写法,在类加载的时候就完成了实例化,避免了多线程的同步问题,适合调用较为频繁类,而且效率较高。

但是缺点也是很明显的,在类加载时就进行实例化,没有达到Lazy Loading (懒加载) 的效果,如果这个实例没用被使用,那么内存就浪费了。

单例模式的典型应用场景

  1. Windows的Task Manager(任务管理器)就是很典型的单例模式。在windows上是不能打开两个windows task manager的, 不信你自己试试看哦ヾ(•ω•`)o

  2. Windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。