设计模式系列—单例设计模式


设计模式系列—单例设计模式文章插图
本文作者:何建辉(公众号:org_yijiaoqian)
前言

  • 23种设计模式速记
前面写了一篇对23种设计模式快速记忆的文章 , 有小伙伴说能不能提供一些案例进行说明 。 设计模式系列文章安排上了 , 本篇就从最常用的单例模式和经常提到的反射机制对单例模式的攻击 。
设计模式系列—单例设计模式文章插图
模式定义保证一个类只有一个实例 , 并且提供一个全局访问点 。
场景说明重量级的对象 , 不需要多个实例 , 如线程池 , 数据库连接池 。
设计模式系列—单例设计模式文章插图
单例模式有八种
  • 饿汉式(静态常量)
  • 饿汉式(静态代码块)
  • 懒汉式(线程不安全)
  • 懒汉式(线程安全 , 同步方法)
  • 懒汉式(线程安全 , 同步代码块)
  • 双重检查(DCL)
  • 静态内部类
  • 枚举
饿汉式(静态常量)
  • 构造器私有化(防止 new)
  • 类的内部创建对象
  • 只向外部暴露一个静态的公共方法(getInstance)
代码示例package com.niuh.designpattern.singleton.v1;/** *饿汉模式(静态变量) *类加载到内存后 , 就实例化一个单例 。 JVM保证线程安全 *简单使用 , 推荐使用 *唯一缺点:不管用到与否 , 类装载时就完成实例化 *Class.forName("") *(话说你不用的 , 你装载它干啥) */public class Singleton {// 1. 构造器私有化(防止new)private Singleton () {}// 2. 本类内部创建对象private final static Singleton instance = new Singleton();// 3. 提供一个公有的静态方法 , 返回实例对象 , 提供给外部使用public static Singleton getInstance() {return instance;}}class SingletonTest01 {public static void main(String[] args) {// 测试Singleton instance1 = Singleton.getInstance();Singleton instance2 = Singleton.getInstance();System.out.println(instance1 == instance2); // trueSystem.out.println("instance1.hashCode=" + instance1.hashCode());System.out.println("instance2.hashCode=" + instance2.hashCode());}}优缺点
  • 优点:写法简单 , 实际上在类装载的时候就完成类实例化 , 避免类线程同步问题 。
  • 缺点:在类装载的时候就完成了实例化 , 没有实现 Lazy Loading 懒加载 的效果 。 如果从始至终就没有使用过这个实例 , 会造成内存的浪费 。
这种方法基于 classloder 机制避免了多线程的同步问题 , 不过 , instance 在类装载时就实例化 , 在单例模式中大多数都是调用 getInstace 方法 , 但是导致类装载的原因有多种 , 因此不能确定有其他的方式(或者其他的静态方法)导致类装载 , 这时候初始化 instance 就没有达到 懒加载 的效果
因此:这种单例模式可用 , 但是可能会造成内存的浪费 。 除非开发人员能肯定 , 此类一定会被用到 , 那么内存就不会被浪费 。
饿汉式(静态代码块)代码示例/** * 饿汉式(静态代码块) */public class Singleton {// 1. 构造器私有化private Singleton() {}// 2. 本类内部创建对象实例private static Singleton instance;// 在静态代码块中 , 创建单例对象static {instance = new Singleton();}// 3. 提供一个公有的静态方法 , 返回实例对象public static Singleton getInstance() {return instance;}}优缺点和上面一种很类似 , 都是在类内部实例化 , 只不过类的实例化放在了静态代码块中 。 类一加载 , 就执行类静态代码块中的代码 。 优缺点和上面一样 。
这种单例模式可用 , 但是如果不用 , 可能会造成内存的浪费 。
懒汉式(线程不安全)代码示例package com.niuh.designpattern.singleton.v3;/** * * 懒汉式(线程不安全) */public class Singleton {private static Singleton instance;// 构造函数私有化private Singleton() {}// 提供一个静态的公共方法 , 当使用到该方法时 , 才创建 instance , 即懒汉式public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}}class SingletonTest02 {public static void main(String[] args) {// 测试for (int i = 0; i< 100; i++) {new Thread(() ->System.out.println(Singleton.getInstance().hashCode())).start();}}}优缺点
  • 起到了 懒加载 的效果 , 但是只能在 单线程下使用;
  • 如果在多线程下 , 一个线程进入了 if(instance == null) 判断语句块 , 可能另外一个线程也通过了这个语句判断 , 这是会产生多个实例 , 所以在多线程环境下不可使用这种方式 。
在实际开发中 , 不要使用这种方式 。
懒汉式(线程安全 , 同步方法)代码示例