当前位置: 首页 > news >正文

北京JAVA基础面试30天打卡04

1. 单例模式的实现方式及线程安全

单例模式(Singleton Pattern)确保一个类只有一个实例,并提供一个全局访问点。以下是常见的单例模式实现方式,以及如何保证线程安全:

单例模式的实现方式
  1. 饿汉式(Eager Initialization)

    • 实现:在类加载时就创建实例(静态初始化)。

    • 代码示例

      public class Singleton {private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}}
      
    • 线程安全:天生线程安全,因为实例在类加载时创建,JVM保证类加载过程是线程安全的。

    • 优缺点:简单,但可能会导致资源浪费(如果实例未被使用)。

  2. 懒汉式(Lazy Initialization)

    • 实现:在第一次调用时创建实例。

    • 代码示例(非线程安全)

      public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}}
      
    • 线程安全问题:多线程环境下,可能多个线程同时判断instance == null,导致多次创建实例。

    • 改进(加锁)

      public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
      }
      
      • 使用synchronized关键字保证线程安全,但锁粒度较大,性能较低。
  3. 双重检查锁(Double-Checked Locking)

    • 实现:在懒汉式基础上优化,使用双重检查和volatile关键字。

    • 代码示例

      收起自动换行

      public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
      }
      
    • 线程安全:volatile防止指令重排序,确保实例初始化完成前其他线程不会访问;双重检查减少锁的开销。

    • 优缺点:性能较高,但代码稍复杂。

  4. 静态内部类(Static Inner Class)

    • 实现:利用静态内部类的延迟加载特性。

    • 代码示例

      public class Singleton {private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}}
      
    • 线程安全:JVM保证静态内部类加载时是线程安全的,且只有在调用getInstance时才加载SingletonHolder,实现懒加载。

    • 优缺点:兼顾懒加载和线程安全,推荐使用。

  5. 枚举单例(Enum Singleton)

    • 实现:利用Java枚举类型的特性。

    • 代码示例

      public enum Singleton {INSTANCE;public void doSomething() {// 业务逻辑}}
      
    • 线程安全:JVM保证枚举的实例化是线程安全的,且能防止反射和序列化破坏单例。

    • 优缺点:简洁、安全,但不适合复杂的初始化逻辑。

保证线程安全的关键点
  • 饿汉式和枚举:天生线程安全,依赖JVM类加载机制。

  • 懒汉式:需加锁(如synchronized)或使用双重检查锁。

  • 双重检查锁:结合volatile和synchronized,防止指令重排序和多线程竞争。

  • 静态内部类:利用JVM类加载机制,延迟加载且线程安全。

  • 序列化和反射攻击

    • 防止反射:构造函数抛出异常或使用枚举。

    • 防止序列化破坏:在类中添加

      readResolve

   private Object readResolve() {return instance;

2. 策略模式(Strategy Pattern)

定义

策略模式是一种行为型设计模式,定义一系列算法(策略),将每个算法封装起来,并使它们可以互换。客户端可以根据需要选择不同的策略,而不改变调用代码。

核心组成
  • 抽象策略接口(Strategy):定义算法的接口。
  • 具体策略类(ConcreteStrategy):实现具体算法。
  • 上下文类(Context):持有策略接口的引用,负责调用具体策略。
代码示例
// 策略接口interface Strategy {int execute(int a, int b);
}// 具体策略:加法
class AddStrategy implements Strategy {@Overridepublic int execute(int a, int b) {return a + b;}
}// 具体策略:减法class SubtractStrategy implements Strategy {@Overridepublic int execute(int a, int b) {return a - b;}
}// 上下文class Context {private Strategy strategy;public void setStrategy(Strategy strategy) {this.strategy = strategy;}public int executeStrategy(int a, int b) {return strategy.execute(a, b);}
}// 使用public class Main {public static void main(String[] args) {Context context = new Context();context.setStrategy(new AddStrategy());System.out.println(context.executeStrategy(5, 3)); // 输出 8context.setStrategy(new SubtractStrategy());System.out.println(context.executeStrategy(5, 3)); // 输出 2}}
使用场景
  • 多种算法或行为:当一个类有多种行为,且这些行为可以根据上下文动态切换时(如支付方式:微信、支付宝、银行卡)。

  • 避免条件语句:替代大量if-else或switch语句,使代码更清晰。

  • 算法独立性:需要将算法与客户端代码解耦,方便扩展和维护。

  • 典型案例

    • 排序算法选择(如快速排序、归并排序)。
    • 支付系统(不同支付方式)。
    • 游戏中的角色技能(不同技能效果)。
优缺点
  • 优点:灵活、可扩展,符合开闭原则;代码复用性高。
  • 缺点:客户端需要了解所有策略;策略类可能较多。

3. 模板方法模式(Template Method Pattern)

定义

模板方法模式是一种行为型设计模式,定义一个操作的算法骨架,将某些步骤延迟到子类实现。父类控制算法流程,子类提供具体实现。

核心组成
  • 抽象模板类(AbstractClass):定义算法骨架(模板方法)和抽象方法。
  • 具体子类(ConcreteClass):实现抽象方法,提供具体逻辑。
代码示例
// 抽象模板类abstract class AbstractClass {// 模板方法,定义算法骨架public final void templateMethod() {step1();step2();step3();}protected abstract void step1();protected abstract void step2();protected void step3() { // 可选的钩子方法 也就是子类可以选择性进行重写,不重写默认执行父类方法System.out.println("Default step3");}
}// 具体子类class ConcreteClass extends AbstractClass {@Overrideprotected void step1() {System.out.println("ConcreteClass: Step 1");}@Overrideprotected void step2() {System.out.println("ConcreteClass: Step 2");}@Overrideprotected void step3() {System.out.println("ConcreteClass: Custom Step 3");}
}// 使用public class Main {public static void main(String[] args) {AbstractClass process = new ConcreteClass();process.templateMethod();}}
使用场景
  • 固定算法骨架:当多个类共享相同的算法流程,但部分步骤的实现不同(如数据处理流程:读取、处理、保存)。

  • 代码复用:通过父类定义公共逻辑,子类只实现差异化部分。

  • 控制子类扩展:通过final模板方法限制子类修改算法结构。

  • 典型案例

    • 框架中的生命周期方法(如Spring的ApplicationContext初始化)。
    • 游戏开发中关卡流程(加载、运行、结束)。
    • 报表生成(数据采集、格式化、输出)。
优缺点
  • 优点:提高代码复用性;算法结构统一,易于维护;符合开闭原则。

  • 缺点:子类数量可能增多;父类设计复杂时可能限制灵活性。

  • 使用场景适合抽象类适合接口
    需要代码复用✅ 适合,支持方法和成员变量实现❌ 不适合(除非 default 方法)
    表示“是什么”(is-a)✅ 抽象类适合建层次结构❌ 接口更适合“能做什么”
    表示“能做什么”(has ability to)✅ 非常适合,比如 Serializable, Runnable
    要求多个类共享部分逻辑✅ 用抽象类抽取通用部分❌ 接口不适合写逻辑实现
    实现多个类型/能力组合❌ 不能多继承✅ 接口天生支持多继承

总结对比

  • 单例模式:确保单一实例,关注对象创建,需考虑线程安全(如双重检查锁、静态内部类)。
  • 策略模式:关注行为切换,适合动态选择算法,解耦客户端与算法实现。
  • 模板方法模式:关注算法骨架,适合固定流程但细节可变,强调继承和复用。

拓展:责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,用于将请求的发送者和接收者解耦,使多个对象都有机会处理这个请求。该模式将处理请求的对象组成一条链,请求沿着这条链传递,直到被某个对象处理为止。

结构图(类图)

Client --> Handler1 --> Handler2 --> Handler3 --> …
核心类图包括:

Handler(抽象处理者)

定义处理请求的接口。

持有下一个处理者的引用。

ConcreteHandler(具体处理者)

实现请求处理的逻辑。

如果自己不能处理,则将请求转发给下一个处理者。

Client(客户端)

创建处理链,并将请求传入第一个处理者。

** 应用场景
审批流程(如:员工请假、软件发布等)**

Java Web 的 Filter 过滤器链

Spring Security 的认证授权链

Netty 的 ChannelPipeline

🧑‍💻 Java 示例(审批流程)
比如一个请假流程,组长可以审批 1 天,经理可以审批 3 天,总监可以审批 7 天:

抽象处理者


```java
public abstract class LeaveHandler {protected LeaveHandler next;public void setNext(LeaveHandler next) {this.next = next;}public abstract void handleRequest(int days);
}

具体处理者

public class TeamLeader extends LeaveHandler {@Overridepublic void handleRequest(int days) {if (days <= 1) {System.out.println("组长审批了 " + days + " 天的假期");} else if (next != null) {next.handleRequest(days);}}
}public class Manager extends LeaveHandler {@Overridepublic void handleRequest(int days) {if (days <= 3) {System.out.println("经理审批了 " + days + " 天的假期");} else if (next != null) {next.handleRequest(days);}}
}public class Director extends LeaveHandler {@Overridepublic void handleRequest(int days) {if (days <= 7) {System.out.println("总监审批了 " + days + " 天的假期");} else {System.out.println("假期太长,不批准");}}
}

客户端调用

public class Client {public static void main(String[] args) {LeaveHandler teamLeader = new TeamLeader();LeaveHandler manager = new Manager();LeaveHandler director = new Director();teamLeader.setNext(manager);manager.setNext(director);teamLeader.handleRequest(2); // 输出:经理审批了 2 天的假期teamLeader.handleRequest(6); // 输出:总监审批了 6 天的假期teamLeader.handleRequest(10); // 输出:假期太长,不批准}
}

1.责任链模式的优点?
解耦请求发送者和接收者。
动态调整处理链,灵活性高。
单一职责,每个处理者专注特定请求。
2.缺点?
请求可能未被处理。
链过长影响性能。
调试复杂。

3.使用场景?
日志系统(如不同级别日志处理)。
事件处理(如 GUI 事件传递)。
审批流程(如逐级审批)。

4.如何避免请求未被处理?
设置默认处理者。
确保链配置完整。

http://www.dtcms.com/a/319937.html

相关文章:

  • 一文入门 matplotlib:从基础图表到数据可视化初体验
  • git branch -a无法查看最新的分支
  • CNB私有化部署Dify(零成本)教程
  • 操作系统1.4:操作系统的体系结构
  • ollama 运行gpt-oss 系列教程
  • Numpy科学计算与数据分析:Numpy数组创建与应用入门
  • DevOps简单教程应用
  • ⭐CVPR2025 RoboBrain:机器人操作的统一大脑模型[特殊字符]
  • Redis(八):Redis高并发高可用(哨兵Sentinel)
  • 上海一家机器人IPO核心零部件依赖外购, 募投计划频繁修改引疑
  • QDataStream入门
  • Redis实战(8) -- 分布式锁Redission底层机制
  • 如何解决用阿里云效流水线持续集成部署Nuxt静态应用时流程卡住,进行不下去的问题
  • 基于 MATLAB 的 QPSK 调制、解调、通过高斯信道的误码率计算,并绘制误码率图和眼图、星座图
  • 火山引擎接入豆包AI(纯前端调用api的方式)
  • Java 大视界 -- Java 大数据在智能教育在线课程互动优化与学习体验提升中的应用(386)
  • E频段芯片解决方案
  • npm 与 npx 区别详解。以及mcp中npx加载原理。
  • 2025年生成式大模型部署与推理优化全景解析
  • 14天搞定Excel公式:告别加班,效率翻倍!
  • 【YOLOv8改进 - 上采样】EUCB:(Efficient Up-convolution Block,高效上卷积块)实现特征图尺度匹配和高效上采样
  • 网络编程基石:域名系统与默认端口号详解
  • 文章采集发布Destoon网站技巧
  • C语言函数与预编译:模块化编程的精髓
  • 【AI论文】细胞锻造(CellForge):虚拟细胞模型的智能体化设计
  • 上岸AAAI 2025:自适应框架+前沿算法,顶会热点方向
  • 【VLLM篇】:原理-实现
  • 【论文阅读】基于元模型的体系知识图谱构建
  • spring boot学习计划
  • 什么是AI Agents