Day13
1. Java类加载过程会遇到哪些问题?
类重复加载(ClassCastException):即使是同一个
class
文件,但如果由不同的类加载器加载,它们会被认为是不同的类。
- 解决方法:明确类加载器的使用,尽量共享类加载器或统一加载入口。
类找不到(ClassNotFoundException):运行时通过反射或动态加载类(如
Class.forName("com.test.MyClass")
)。原因是类不在当前类加载器的 classpath;可能 JAR 包未引入或路径错误。NoClassDefFoundError:编译时类存在,但运行时 JVM 加载类失败。原因是依赖的类在运行时缺失(如某个 JAR 被删除);静态初始化失败,导致类加载失败(例如抛出异常)。
类加载死循环:A 类静态字段依赖 B 类,B 类又依赖 A。可能会导致栈溢出或者某个类初始化失败。
双亲委派导致类加载冲突(或不加载):自定义类加载器加载类时,父加载器已经加载了同名类;尤其在加载 JDK 核心类重定义版本时会被拦截。
- 打破双亲委派(如 SPI、Tomcat 插件类加载器)
- 明确自定义加载逻辑
初始化异常(ExceptionInInitializerError):在类初始化(执行
static{}
块或静态字段赋值)抛出异常。原因是例如除零、空指针等导致类初始化失败。一旦初始化失败,该类就不能再被使用,JVM 会抛出该错误。
2. 介绍下MySQL的索引?
索引是提高数据库查询效率的一种数据结构。就像书的目录页,可以快速定位到想要查找的内容。在没有索引时,MySQL 只能全表扫描,查询效率低;有了索引后,可以大幅提高 SELECT 查询的速度,尤其是大数据量时。
MySQL 的 InnoDB 存储引擎使用的是 B+ 树结构来组织索引数据。B+ 树是一种多路平衡查找树,所有的实际数据都保存在叶子节点,非叶子节点仅存储索引键和指向子节点的指针。相比于 B 树,B+ 树的非叶子节点不存储具体数据,使得单个节点可以容纳更多索引项,从而降低树的高度,提高查询效率。InnoDB 中的主键索引是聚簇索引,数据以主键顺序存储在 B+ 树的叶子节点中,而普通索引是二级索引,其叶子节点存储的是对应主键的值,需要通过回表操作获取完整数据。B+ 树叶子节点之间还通过指针连接成有序链表,便于范围查询和排序操作。因此,B+ 树结构能够在保持有序的同时,兼顾查找效率和磁盘访问性能,是数据库索引的理想选择。
索引类型 | 简介 |
---|---|
主键索引(Primary Key) | 默认创建,唯一且非空 |
唯一索引(Unique) | 保证列值唯一,但可为空 |
普通索引(Index) | 最基本的加速搜索用 |
复合索引(Composite) | 多列组成的联合索引 |
前缀索引(Prefix) | 针对长文本字段做部分前缀索引 |
全文索引(Fulltext) | 用于自然语言搜索(如文章) |
空间索引(Spatial) | 针对 GIS 类型的数据 |
3. MySQL订阅binlog的中间件是什么?有什么用?
阿里开源在 Canal,它是一个用于订阅和消费 MySQL Binlog 的中间件。它通过模拟 MySQL 主从赋值的交互协议,将自己伪装成一个 MySQL 的从节点,向主库发送 dump 请求。主库接收到请求后,会将实时生成的 Binlog 日志推送给 Canal。Canal 接收后对 Binlog 的字节流进行解析,提取出数据库的变更信息(如 INSERT、UPDATE、DELETE),并将其转换为结构化的增量数据格式,供下游系统(如 Kafka、Redis、Elasticsearch等)订阅使用。种机制广泛应用于数据库异构同步、缓存自动更新、实时数据分析、搜索引擎同步等场景,是构建高实时数据链路的重要组件。
通过 Canal 订阅 Binlog 并发送变更日志到 MQ,再由消费者订阅消息并删除缓存,同时结合 ACK 确认机制,可以实现 MySQL 与 Redis 缓存之间的强一致性控制,是目前微服务系统中非常实用的一种缓存同步策略。
4. 限流算法有哪些?
- 固定窗口算法(Fixed Window):将时间划分为固定长度的窗口(如每秒、每分钟),每个窗口内设置一个计数器,记录请求次数。一旦达到设定阈值,新请求将被拒绝,直到下一个时间窗口开始,计数器重置。
![]()
- 举例:允许每秒 100 个请求,若第 0.999 秒来了 100 个,第 1.000 秒又来了 100 个,系统实际上在瞬间处理了 200 个请求。(容易发生“突刺流量”(窗口临界点前后大量请求累计)问题。)
- 滑动窗口算法(Sliding Window):把时间窗口进一步划分为多个小窗口(例如每秒分成 10 个小格,每个 100ms),记录每个小格的请求数。当前时间点的总请求数 = 当前滑动窗口中的所有小格的请求总和。如果总和 ≤ 限流值 就放行,否则限流。
- 漏桶算法(Leaky Bucket):可以把它想象成一个漏水的桶,请求以任意速率进入桶中,但系统处理速率是固定的(水匀速露出)。如果桶满了(处理不过来),则新请求会被丢弃或排队。
- 桶就是“缓冲队列”
- 控制的是处理速率:固定速率漏水
- 超出容量的就会被丢弃
- 令牌桶算法(Token Bucket):系统以恒定速率往桶中放令牌(比如每 100ms 放 1 个),请求到来时必须先拿到一个令牌才能继续处理。若桶满了就不再生成新令牌;请求来了但无令牌就被拒绝。
- 控制的是“请求通行的资格”
- 令牌是“许可证”
- 有令牌就放行,没有就限流
- 允许短时间内的突发流量,因为可以积攒令牌