0%

线程死锁:原理、成因与解决方案

线程死锁是多线程编程中常见的隐性问题,指两个或多个线程相互等待对方持有的资源,导致所有线程陷入无限期阻塞的状态。死锁一旦发生,程序往往无法自动恢复,需通过代码设计规避或手动干预解决。

死锁的核心成因

死锁的产生必须同时满足以下四个必要条件,缺一不可:

  1. 互斥条件
    资源具有排他性,同一时间只能被一个线程占用(如synchronized锁、文件句柄等)。
  2. 请求与保持条件
    线程持有部分资源,同时又请求其他线程已持有的资源,且不释放自身已占有的资源。
  3. 不剥夺条件
    线程已获得的资源,在未主动释放前,不能被其他线程强行剥夺(如 Java 的内置锁无法被强制释放)。
  4. 循环等待条件
    多个线程形成环形等待链,每个线程都在等待下一个线程持有的资源(如线程 A 等线程 B 的资源,线程 B 等线程 A 的资源)。

死锁示例代码

以下是一个典型的死锁场景:两个线程分别持有对方需要的锁,且都不释放自身的锁。

阅读全文 »

Spring Boot 集成 Redis 乱码问题详解:原因分析与解决方案

在 Spring Boot 集成 Redis 时,若使用默认配置的 RedisTemplate 操作字符串,常出现 key/value 乱码(如前缀含 \xac\xed\x00\x05t\x00\x03 等特殊字符)。核心原因是 RedisTemplate 默认采用 JdkSerializationRedisSerializer 序列化方式(基于 JDK 原生序列化,会生成二进制数据),而 StringRedisTemplate 或自定义序列化配置可彻底解决该问题。从 “乱码原因→两种解决方案→序列化对比→实战示例” 四个维度,系统讲解 Redis 乱码的解决方法。

乱码的根本原因:默认序列化方式不匹配

首先需明确:Redis 本身是 二进制安全的键值存储,不限制数据格式,但 Spring Boot 提供的 RedisTemplate 默认序列化方式会导致 “人类不可读” 的二进制数据,被误认为 “乱码”。

1. RedisTemplate 默认序列化配置

RedisTemplate 对不同类型的序列化器默认配置如下:

数据类型 默认序列化器 序列化结果特点
Key(键) JdkSerializationRedisSerializer 生成二进制数据,前缀含特殊字符(如 \xac\xed),乱码
Value(值) JdkSerializationRedisSerializer 同上,二进制数据,不可读
Hash Key JdkSerializationRedisSerializer 同上
Hash Value JdkSerializationRedisSerializer 同上
问题根源:JdkSerializationRedisSerializer 的特性
  • 原理:基于 JDK ObjectOutputStream 实现序列化,要求被序列化的对象实现 Serializable 接口;
  • 结果:序列化后的数据是 二进制字节数组,存储到 Redis 后显示为乱码(如 \xac\xed\x00\x05t\x00\x03key);
  • 场景不匹配:若仅操作字符串(如 String 类型的 key/value),二进制序列化完全没必要,且导致乱码。

2. 示例:默认配置的乱码效果

使用默认 RedisTemplate 存储字符串:

阅读全文 »

单例模式(Singleton Pattern)详解

单例模式是创建型设计模式中最常用的模式之一,其核心是保证一个类在系统中仅有一个实例,并提供全局访问点。这种模式适用于需要统一控制资源、避免重复创建对象的场景(如配置管理器、日志工具等)。

单例模式的核心原则

实现单例模式需遵循四大原则:

  1. 构造方法私有:防止外部通过new关键字创建实例。
  2. 以静态方法或枚举返回实例:提供全局访问接口。
  3. 确保实例唯一:通过设计避免多线程或其他场景下的重复创建。
  4. 防止反序列化重复实例:确保对象序列化 / 反序列化后仍为单例。

单例模式的两种核心实现方式

根据实例化时机的不同,单例模式分为饿汉式(立即加载)和懒汉式(延迟加载)。

1. 饿汉式(Eager Initialization)

核心思想

类加载时立即创建实例,通过类加载机制保证线程安全。

实现代码
阅读全文 »

HTTP 缓存:提升 Web 性能的核心机制

HTTP 缓存是优化 Web 性能的关键技术,通过在客户端(如浏览器)存储已请求的资源副本,减少重复向服务器请求的次数,从而降低网络延迟、节省带宽并提升用户体验。其核心逻辑是:客户端首次请求资源时缓存数据,后续请求优先使用缓存(若有效),否则向服务器重新获取

HTTP 缓存的基本原理

HTTP 缓存的工作流程可概括为:

  1. 首次请求:客户端向服务器请求资源,服务器返回资源并在响应头中附加缓存规则(如过期时间、修改标识)。
  2. 缓存存储:客户端将资源和缓存规则一起保存到本地缓存(如浏览器的内存、磁盘)。
  3. 后续请求:客户端先检查本地缓存是否有效:
    • 若缓存有效,直接使用缓存数据(缓存命中);
    • 若缓存无效,向服务器重新请求资源,并更新缓存(缓存失效)。

HTTP 缓存的两类核心规则

HTTP 缓存通过响应头中的字段定义缓存策略,主要分为基于过期时间的缓存基于资源修改的缓存两大类,两者可协同工作。

基于过期时间的缓存:Expires 与 Cache-Control

这类规则通过指定资源的 “有效期”,让客户端直接判断缓存是否可用,无需向服务器确认,属于强缓存(不发起网络请求,直接使用缓存)。

阅读全文 »