揣一尾游鱼yu头像

单例模式 & 多例模式笔记

⚠️ 区分: 【设计模式:单例模式】自己写代码控制类只能产生一个对象 【Spring scope singleton】Spring容器帮你控制bean只创建一份,不是同一个东西

一、单例模式(Singleton)

核心:保证一个类在整个程序中,有且仅有一个实例对象,提供全局访问点。 使用场景:工具类、连接池、线程池、配置文件对象、日志对象,不需要多个实例。

分类

1. 饿汉式(静态常量,简单、线程安全,考试最常写)

package com.qcby;
//单例模式-饿汉式 传统实现代码
public class Singleton2 {
   
//私有构造方法
    private Singleton2(){ };
   
//类加载时就实例化对象 加static
   
private static Singleton2 obj=new Singleton2();

   
public static Singleton2 getInstance(){
       
return  obj;
    }
}

通过static关键字,在类加载时创建对象。

特点:

  • 类加载的时候直接实例化对象 能够在第一时间实例化对象,供其他方法使用,是拿空间换时间的方案
  • 优点:写法简单、天然线程安全,没有并发问题
  • 缺点:类加载就创建,不用它也会占用内存,没有懒加载

优化实现:

上述传统方式中,由于类加载时就实例化对象,因此当我们调用这个类的其它静态方法时,也会触发类加载,从而实例化单例独享,会导致空间的暂时浪费。

由于静态内部类中的对象不会默认加载,直到调用了获取该内部类属性的方法。因此可用静态内部类封装静态实例变量。

优化实现代码:

class Singleton{

// 私有构造函数

private Singleton() {}

// 静态内部类

private static class SingletonHolder {

private static Singleton instance = new Singleton();

}

public static Singleton getInstance(){

     return SingletonHolder.instance;

   }

}

种种实现方式中,最推荐这种优化后的饿汉式实现,利用static保证线程安全,利用静态内部类节约了空间,实现lazy-loading(懒加载),而且代码非常简短,可谓一箭三雕。

2. 懒汉式(双重检查锁 DCL,开发常用,懒加载+线程安全)

传统实现代码:

package com.qcby;
//单例模式-懒汉式 传统实现代码
class  Singleton{
   
//声明一个Singleton对象为obj
   
private static Singleton obj;
   
//设置私有构造方法
    private Singleton(){}
   
//加锁保证obj只能实例化一次,时间换空间
    public static synchronized  Singleton getInstance(){

       
if(obj == null){
           
obj=new Singleton();
        }
       
return    obj;
    }
}

传统实现方式中,每次获取实例都要被synchronized关键字串行化,即使已经生成了对象实例。

而我们加锁的目的是为了防止生成多个实例,因此其实只需要对生成实例的代码加锁,生成实例后,可支持并发访问,提高性能。

优化实现代码:

package com.qcby;
//单例模式-懒汉式 优化实现代码
public class Singleton1 {
   
private  volatile static Singleton1  obj;
   
//获取实例对象的方法
    public static Singleton1  getInstance(){
       
//如果已有实例则直接返回,不走锁
        if(obj==null){
           
//仅在没生成实例时加锁控制,使并发访问串行化
            synchronized(Singleton1.class){
               
//多个线程会按序执行到此处,需要再次检查是否已经实例化
                if(obj==null){
                   
obj = new Singleton1();
                }
            }
        }
       
return  obj;
    }
}

优化实现 由于检查了两次对象是否已经实例化,因此该方法又被称为“双检法”,能够保证线程安全的同时提升对象实例化后的调用性能。

特点:

  • 懒加载:调用getInstance()才创建对象
  • volatile关键字:禁止指令重排序(考点!)
  • 优点:用时才创建,线程安全,效率高
  • 缺点:写法复杂

❌ 不推荐:不加锁的懒汉式,多线程下会创建多个对象,线程不安全

单例模式要点

  1. 构造方法私有化 private → 外面不能 new
  2. 静态变量保存唯一实例
  3. 提供静态方法 getInstance() 获取这个唯一对象
  4. 破坏单例的方式:反射、序列化反序列化

二、多例模式(Multiton)

核心:限制一个类,只能产生固定数量的多个实例,不是无限new,也不是只能1个。

区别:普通类随便new无数个;多例模式控制实例总数固定。 场景:比如数据库连接固定3个连接、线程池固定几个worker。

示例(固定2个实例)

package com.qcby;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class Multiton {
   
// map用来存我们提前建好的实例,key标记每个对象
    private static Map<String, Multiton> map = new HashMap<>();
   
// 规定一共只能创建 2 个实例,可以修改这个数字
    private static final int COUNT = 2;

   
// 静态代码块:类加载的时候执行,提前把2个对象一次性创建好放进map
   
static {
       
for (int i = 1; i <= COUNT; i++) {
           
map.put("key"+i, new Multiton());
        }
    }

   
// 私有构造方法!重点
    // 外面不能 new Multiton(),防止别人随便造新对象,破坏“数量固定”的规则
    private Multiton(){}

   
// 对外获取实例的方法:随机从已经建好的2个里面返回一个
    public static Multiton getInstance(){
       
// 拿到map里所有key,转成数组:["key1","key2"]
       
String[] keys = map.keySet().toArray(new String[0]);
       
// 随机生成 0 或者 1
       
int index = new Random().nextInt(COUNT);
       
// 返回对应key的对象
        return map.get(keys[index]);
    }
}

特点:

  1. 构造方法私有,外部不能随意new
  2. 在静态代码块提前创建好固定个数对象
  3. 外部只能从已经创建好的里面拿,不能新增
  4. 同一个key拿到同一个对象;不同key是不同对象

补充:我们平时随便new User()这种,叫普通无限制实例,不属于多例模式! ✅ 多例 = 实例数量可控、固定;不是“可以new好几个”就叫多例


三、对比表格

项目

单例模式(Singleton)

多例模式(Multiton)

实例数量

只能 1 个

固定有限多个(比如 2、3 个)

构造器

private 私有

private 私有

对象创建时机

饿汉:类加载;懒汉:调用方法时

一般静态代码块提前创建全部

获取方式

getInstance (),永远返回同一个

从预先建好的一批里面获取

目的

全局唯一对象,节省资源

控制实例上限,避免无限创建

四、高频易混区分

  1. 设计模式 单例模式:自己写Java代码,控制这个类只能造1个对象
  2. Spring bean scope="singleton":Spring容器里面这个bean只一份,底层不是单例模式,只是容器行为
  3. Spring bean scope="prototype":每次getBean新建对象,不是设计模式的多例! prototype是无限新建,多例模式是数量固定

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2302_81838100/article/details/169463796

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--