参考答案:
RabbitMQ 提供多种工作模式,核心区别在于交换机(Exchange)的类型和消息路由机制:
- 简单模式(Simple):直连交换机(Direct),一对一消息队列。
- 工作队列模式(Work Queues):多个消费者竞争同一队列的消息,实现负载均衡。
- 发布 / 订阅模式(Publish/Subscribe):扇形交换机(Fanout),将消息广播到所有绑定队列。
- 路由模式(Routing):直连交换机(Direct),按路由键(Routing Key)精确匹配队列。
- 主题模式(Topics):主题交换机(Topic),支持通配符(
*、#)模糊匹配。 - RPC 模式:通过回调队列实现远程过程调用。
关键点:交换机类型决定消息路由规则,队列绑定决定消息接收方。
2. 简述 GC(垃圾回收)的工作原理及常见算法
参考答案:
GC 的核心目标是自动回收不再使用的内存,主要基于 “可达性分析” 算法:
- 标记阶段:从根对象(静态变量、栈变量等)出发,标记所有可达对象。
- 清除阶段:回收未被标记的对象。
常见算法:
- 标记 – 清除(Mark-Sweep):基础算法,易产生内存碎片。
- 标记 – 整理(Mark-Compact):清除后整理内存,减少碎片。
- 复制算法(Copying):将内存分为两块,存活对象复制到另一块,高效但浪费空间。
- 分代收集(Generational):按对象生命周期分代(新生代、老年代),不同代采用不同算法。
JVM 参数调优:
-Xms/-Xmx:堆初始 / 最大大小-XX:+UseG1GC:使用 G1 垃圾回收器
3. Docker 基础命令及容器化部署流程
参考答案:
基础命令:
bash
# 镜像操作
docker pull [镜像名] # 拉取镜像
docker images # 查看本地镜像
docker build -t [标签] . # 构建镜像
# 容器操作
docker run -d -p 80:80 --name [容器名] [镜像名] # 运行容器
docker ps # 查看运行中容器
docker logs [容器ID] # 查看日志
docker exec -it [容器ID] bash # 进入容器
docker stop/rm [容器ID] # 停止/删除容器
部署流程:
- 编写
Dockerfile定义应用环境。 - 构建镜像:
docker build -t myapp:1.0 . - 运行容器:
docker run -d -p 8080:8080 myapp:1.0 - 持久化数据(可选):挂载卷
-v /host/path:/container/path。
4. 简述 MySQL 事务特性及隔离级别
参考答案:
ACID 特性:
- 原子性(Atomicity):事务中的操作要么全执行,要么全回滚。
- 一致性(Consistency):事务执行前后数据保持一致状态。
- 隔离性(Isolation):多个事务相互隔离,避免干扰。
- 持久性(Durability):事务提交后结果永久保存。
隔离级别:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | 允许 | 允许 | 允许 |
| READ COMMITTED | 禁止 | 允许 | 允许 |
| REPEATABLE READ | 禁止 | 禁止 | 允许 |
| SERIALIZABLE | 禁止 | 禁止 | 禁止 |
MySQL 默认:REPEATABLE READ(通过 MVCC 解决幻读)。
5. 如何优化 MySQL 查询性能?
参考答案:
- 索引优化:
- 为高频查询字段创建索引(避免全表扫描)。
- 使用复合索引时遵循 “最左前缀原则”。
- 避免索引失效(如函数操作、模糊查询前置通配符)。
- 查询优化:
- 避免
SELECT *,仅查询需要的字段。 - 使用
EXPLAIN分析查询执行计划。 - 减少子查询,优先使用连接(JOIN)。
- 避免
- 架构优化:
- 分库分表(垂直拆分字段、水平分表)。
- 读写分离(主库写、从库读)。
- 配置优化:
- 调整
innodb_buffer_pool_size(建议物理内存的 70-80%)。 - 定期执行
OPTIMIZE TABLE整理碎片。
- 调整
6. Spring Bean 的生命周期
参考答案:
- 实例化:通过构造器或工厂方法创建 Bean 对象。
- 属性注入:依赖注入(如 @Autowired、Setter 方法)。
- 初始化回调:
- 实现
InitializingBean的afterPropertiesSet()方法。 - 使用
@PostConstruct注解。 - 自定义
init-method。
- 实现
- BeanPostProcessor 处理:初始化前后的增强处理(如 AOP 代理)。
- 使用:Bean 就绪,可被应用程序调用。
- 销毁回调:
- 实现
DisposableBean的destroy()方法。 - 使用
@PreDestroy注解。 - 自定义
destroy-method。
- 实现
7. 简述 Java 并发编程中的线程池
参考答案:
线程池优势:
- 降低线程创建 / 销毁开销,提高响应速度。
- 控制最大并发线程数,避免资源耗尽。
- 提供任务管理机制(如定时任务、拒绝策略)。
核心参数:
java
ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 空闲线程存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 任务队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略
);
常见拒绝策略:
AbortPolicy(默认):抛出异常。CallerRunsPolicy:调用者线程执行任务。DiscardPolicy:直接丢弃任务。DiscardOldestPolicy:丢弃队列中最老的任务。
8. synchronized 与 ReentrantLock 的区别
参考答案:
| 特性 | synchronized | ReentrantLock |
|---|---|---|
| 锁实现方式 | JVM 层面(内置锁) | API 层面(java.util.concurrent) |
| 锁获取方式 | 隐式(自动释放) | 显式(需手动调用 unlock) |
| 可中断性 | 不可中断 | 可中断(lockInterruptibly) |
| 公平性 | 非公平 | 可设置公平 / 非公平 |
| 条件变量 | 单一 wait/notify 机制 | 多个 Condition 对象 |
选择建议:
- 简单场景优先使用
synchronized(语法简洁)。 - 需要高级特性(如可中断锁、公平锁)时使用
ReentrantLock。
9. 简述 Java NIO 与传统 IO 的区别
参考答案:
| 特性 | 传统 IO(BIO) | NIO(New IO) |
|---|---|---|
| 阻塞模式 | 阻塞(线程等待 IO 完成) | 非阻塞(线程可继续处理其他任务) |
| 核心组件 | InputStream/OutputStream | Channel、Buffer、Selector |
| 数据处理 | 字节流 / 字符流 | 缓冲区(Buffer) |
| 适用场景 | 连接数少且固定的场景 | 高并发、连接数多的场景(如 Web 服务器) |
示例:
NIO 通过 Selector 实现单线程管理多个 Channel,避免了 BIO 的线程阻塞问题。
10. 如何排查 Java 内存泄漏问题?
参考答案:
- 监控工具:
- 使用
jstat查看 GC 频率和内存占用。 - 使用
jmap生成堆转储文件(Heap Dump)。 - 使用工具(如 MAT、VisualVM)分析 Dump 文件,找出大对象和引用链。
- 使用
- 常见原因:
- 静态集合持有对象引用(如 HashMap 未清理)。
- 未关闭的资源(如 IO 流、数据库连接)。
- 内部类持有外部类引用。
- 预防措施:
- 使用弱引用(WeakReference)存储缓存数据。
- 在
finally块中释放资源。 - 避免静态集合存储大对象。
回答技巧总结:
- 结构化回答:按 “概念解释→核心特性→应用场景→示例 / 对比” 的逻辑展开。
- 结合源码或底层原理:如提到
synchronized时,可简单说明其在 JVM 中的实现(偏向锁、轻量级锁、重量级锁)。 - 案例化:用实际项目经验举例( 项目中,我们通过调整线程池参数解决了 OOM 问题”)。
- 避免空洞:回答算法或机制时,用流程图或步骤描述辅助理解。