2021年9月15日-设计模式之单例模式

第三章:单例设计模式

一、设计模式概述

1)《设计模式》是经典书籍,作者是 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides Design(俗称:“四人组 GOF”)

2)设计模式——design pattern,是某类问题的通用解决方案

3)设计模式分为三种类型,共 23 种

  • 创建者模式:单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式
  • 结构型模式:适配器模式、桥接模式、装饰者模式、组合模式、外观模式、享元模式、代理模式
  • 行为型模式:模板方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式

二、单例设计模式介绍

采取一定的方法保证在整个软件的运行过程中,某个类只能存在一个对象实例,该类会提供一个获取其对象实例的静态方法

三、单例设计模式七种方式

1. 饿汉式(静态常量)

所谓饿汉式,就是在类加载时,对象实例就创建好了

public class Singleton {
    // 类内部创建对象
    private final static Singleton instance = new Singleton();

    // 构造器私有
    private Singleton() {}

    // 提供返回实例的静态方法
    public static Singleton getInstance() {
        return instance;
    }
}

测试一下是否真的只有一个实例(其他方式测试略)

public static void main(String[] args) {
    Singleton instance1 = Singleton.getInstance();
    Singleton instance2 = Singleton.getInstance();
    System.out.println(instance1.hashCode());
    System.out.println(instance2.hashCode());
    System.out.println(instance1 == instance2);
}


/*************** output ***************
460141958
460141958
true
**************************************/
优点缺点
写法简单没有做到懒加载(Lazy Loading)
轻松避免线程同步问题(‾◡◝)如果自始至终都没用到实例,则会造成内存浪费

如果类中除了获取实例的静态方法就没有其他静态方法的话,饿汉式就很好( ̄_, ̄ )

2. 饿汉式(静态代码块)

public class HungrySingleton {
    // 构造亲私有
    private HungrySingleton() {}

    // 类内部创建实例
    private final static HungrySingleton instance;

    static {
        try {
            instance = new HungrySingleton();
        } catch (Throwable e) {
            // 必须抛出一个错误,不然会报 final 未初始化
            // 当然也可以不加 final 关键词
            throw new Error();
        }
    }

    // 提供一个静态方法返回实例
    public static HungrySingleton getInstance() {
        return instance;
    }
}

优缺点同上ㄟ( ▔, ▔ )ㄏ

3. 懒汉式(线程不安全)

所谓懒汉式就是在类加载时并没有创建实例,只有在第一次获取实例对象时才创建

public class LazySington {
    private static LazySington instance;

    private LazySington() {}

    public static LazySington getInstance() {
        if (instance == null) {
            instance = new LazySington();
        }
        return instance;
    }
}
优点缺点
做到了懒加载线程不安全

想象一下有两个线程 A 和 B,当 A 判断 instance 为空后,正要 new 时发生了线程上下文切换,cpu 时间片分给了 B,B new 好对象后,又切换成 A 运行,这时 A 又new 了一遍。

所以上述方式不推荐使用(⊙ˍ⊙)

4. 懒汉式(线程安全,同步方法)

public class LazySington {
    private static LazySington instance;

    private LazySington() {}

    public static synchronized LazySington getInstance() {
        if (instance == null) {
            instance = new LazySington();
        }
        return instance;
    }
}
优点缺点
懒加载效率低
线程同步

实际上只有第一次初始化实例时需要加锁,其他阶段加锁毫无卵用,白白降低并发度

5. 懒汉式(线程安全,同步代码块双重检查)

public class LazySington {
    private static LazySington instance;

    private LazySington() {
    }

    public static LazySington getInstance() {
        if (instance == null) {
            synchronized (LazySington.class) {
                if (instance == null) {
                    instance = new LazySington();
                }
            }
        }
        return instance;
    }
}
优点缺点
懒加载-
线程安全-
效率高-

推荐使用这种单例模式

6. 静态内部类

public class InnerClassSingleton {
    // 构造方法私有化
    private InnerClassSingleton() {}
    
    // 静态内部类
    private static class SingletonInstance {
        private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
    }
    
    // 获取实例的静态方法
    public static InnerClassSingleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}
优点缺点
静态内部类并不会因为类的加载而加载-
所以即使类内有其他静态方法也能做到懒加载-
线程安全-

推荐使用这种单例模式

7. 枚举

enum  EnumSingleton  {
    INSTANCE;

    public void sayHello() {
        System.out.println("hello!");
    }
}

枚举单例本质就是饿汉式(静态代码块),所以只要枚举中没有静态方法造成类加载的话可以推荐使用

四、单例模式的适用场景

1)需要频繁创建销毁的对象

2)创建时耗时或耗费大量资源并且经常用到的对象

3)工具类对象

4)频繁访问数据库或文件的对象(如数据源)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值