单例设计模式

单例设计模式

什么是单例模式

单例(单个的实例)

创建一个唯一的对象
这个类只存在一个实例

单例模式有两种方式

1、饿汉式 2、懒汉式

1、饿汉式

没有使用这个实例也会创建实例,比如调用实例的静态属性也会创建实例
对象,通常是重量级的对象, 饿汉式可能造成创建了对象,但是没有使用
如何保障我们只能创建一个 GirlFriend 对象
步骤[单例模式-饿汉式]

  1. 将构造器私有化
  2. 在类的内部直接创建对象(该对象是 static)
  3. 提供一个公共的 static 方法,返回对象
public class ch {
    public static void main(String[] args) {
        Car car = Car.getInstance();
        System.out.println(car.name);
    }
}
class Car{
    private String name;
    //在类加载时创建Car对象,只执行一次
    //为了在静态方法中访问需要定义为static
    private static Car car = new Car("lldwb");
    private Car(String name){
        System.out.println("创建一个Car类");
        this.name = name;
    }
    //提供一个公共的静态方法,返回Car对象
    public static Car getInstance(){
        return car;
    }
}

2、懒汉式

调用对象时创建这个实例,比如调用实例的静态属性不会创建实例。
如何保障我们只能创建一个 GirlFriend 对象
步骤[单例模式-懒汉式]

  1. 将构造器私有化
  2. 在类的内部直接创建对象(该对象是 static)
  3. 提供一个公共的 static 方法,返回对象
  4. 懒汉式,只有当用户使用 getInstance 时,才返回对象, 后面再次调用时,会返回上次创建的 cat 对象
class Car{
    private String name;
    //在类加载时创建Car对象,只执行一次
    //为了在静态方法中访问需要定义为static
    private static Car car;
    private Car(String name){
        System.out.println("创建一个Car类");
        this.name = name;
    }
    //提供一个公共的静态方法,返回Car对象
    public static Car getInstance(){
        if(car == null){
             car = new Car("lldwb");
        }
        return car;
    }
}

饿汉式 VS 懒汉式

  1. 二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建。
  2. 一个是加载时创建,一个是使用时创建
  3. 饿汉式不存在线程安全问题,懒汉式存在线程安全问题。(多线程中可能创建多个对象)
  4. 饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题。
  5. 在我们javaSE标准类中,java.lang.Runtime就是经典的单例模式

单例模式的使用场景

  1. QQ聊天窗口(只会打开一个窗口)

补充

懒汉式中解决线程安全

  1. 在方法访问修饰符加多线程的同步块(synchronized)
  2. 换饿汉式
  3. 结合静态内部类,代码如下

    public class People {
    private People(){}
    
    /**
     * 使用静态内部类来创建一个唯一的外部类实例
     */
    private static class InnerClass{
        // 创建一个唯一的外部类实例
        private static final People INSTANCE = new People();
    }
    
    /**
     * 对外部提供一个公开的方法获取实例
     * @return
     */
    public static People getInstance(){
        // 当使用InnerClass时才会加载这个内部类,从而初始化People的实例
        // 因为static只会执行一次,所有只有一个People对象
        return InnerClass.INSTANCE;
    }
    }