什么是单例模式
所谓单例模式,即在程序运行期间只会创建一个实例。
特别适用于:创建对象开销极大,需要耗费大量的资源,并且不考虑线程安全。
Java中如何使用单例模式
记住以下两个要点:
- 构造方法是私有的,外部不能创建实例
- 提供一个方法获取实例,用这个方法创建实例并返回
单例模式可以用这个类图表示:
饿汉式:
所谓饿汉式,即为程序初始化时就创建了实例。
实现方式:
public class SingletonA {
// 使用 static 修饰符,程序初始化期间就会创建实例
private static SingletonA instance = new SingletonA();
// 构造方法私有,外部无法调用
private SingletonA() {
try {
// 模拟实际过程中,创建实例可能会占用大量资源的过程
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
System.out.println("创建实例中.......目前进度:"+ i*10.0 + "%");
}
System.out.println("成功创建实例............");
System.out.println("引用地址为:" + this);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 外部只能使用这个方法获取实例
public static SingletonA getInstance() {
return instance;
}
}
测试类:
public class Main {
public static void main(String[] args) {
// 获取实例
SingletonA instance = SingletonA.getInstance();
// 打印实例对象
System.out.println(instance);
// 再次获取实例,验证是否为同一对象
instance = SingletonA.getInstance();
System.out.println(instance);
}
}
运行结果:
创建实例中.......目前进度:0.0%
创建实例中.......目前进度:10.0%
创建实例中.......目前进度:20.0%
创建实例中.......目前进度:30.0%
创建实例中.......目前进度:40.0%
创建实例中.......目前进度:50.0%
创建实例中.......目前进度:60.0%
创建实例中.......目前进度:70.0%
创建实例中.......目前进度:80.0%
创建实例中.......目前进度:90.0%
成功创建实例............
引用地址为:com.study.singleton.SingletonA@1b6d3586
com.study.singleton.SingletonA@1b6d3586
com.study.singleton.SingletonA@1b6d3586
优缺点
优点:
- 线程安全,程序初始化就创建了实例
- 初始化速度快
缺点:
- 对象实例的创建时机不可控
- 可能对象创建后根本没有使用,白白占用资源
懒汉式:
所谓懒汉式,即为只在获取实例时创建实例,在需要时创建,避免了资源占用。
由于创建实例的过程是在程序运行时进行的,因此需要考虑在多线程情况下避免创建多个实例。
实现方式:
public class SingletonB {
// instance 初始为 null,不占内存
private static SingletonB instance;
// 构造方法私有,外部无法调用
private SingletonB () {
try {
// 模拟实际过程中,创建实例可能会占用大量资源的过程
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
System.out.println("创建实例中.......目前进度:"+ i*10.0 + "%");
}
System.out.println("成功创建实例............");
System.out.println("引用地址为:" + this);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 使用同步锁,防止多个线程重复创建实例
public static synchronized SingletonB getInstance() {
if (instance == null) {
instance = new SingletonB();
}
return instance;
}
}
优缺点
懒汉式的优点:
- 不会造成内存浪费
缺点:
- 效率较低,每个线程获取实例时,都需要同步锁
小结
单例模式很适合在创建实例过程资源开销大的场景下使用,例如 Spring 中的 bean 加载就使用到了单例模式,一个 bean 可能需要多个 bean 成员变量,这些 bean 成员变量有需要其他 bean 成员变量,可以想象实例化的过程是十分重量级的。
因此,使用单例模式可以让对象只实例化一次,往后每次获取实例都获取同一个,避免反复创建,消耗资源。
单例模式有两种基本的实现方式,饿汉式和懒汉式,饿汉式创建时间不可控,但是创建资源不需要考虑线程安全,而懒汉式则反之,实际应用根据情况选用。
单例模式也有一个问题,不适合用来保存有状态的成员变量,多线程状况下,多个线程同时操作单例实例,可能会破坏实例的状态。因此,单例模式更适合无状态的实例。
本文含有隐藏内容,请 开通VIP 后查看