Java设计模式——创建型模式:单例模式

发布于:2023-01-21 ⋅ 阅读:(494) ⋅ 点赞:(0)

什么是单例模式

所谓单例模式,即在程序运行期间只会创建一个实例。

特别适用于:创建对象开销极大,需要耗费大量的资源,并且不考虑线程安全。

Java中如何使用单例模式

记住以下两个要点:

  1. 构造方法是私有的,外部不能创建实例
  2. 提供一个方法获取实例,用这个方法创建实例并返回

单例模式可以用这个类图表示:

Singleton
-singleton
-Singleton()
+getInstance()

饿汉式:

所谓饿汉式,即为程序初始化时就创建了实例。

实现方式:

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 后查看