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

Java实习面试记录

JMM 中的三大特性

可见性

多个线程访问同一变量时,一个线程修改的值,其他线程能否及时看到

  • volatile 能保证可见性:
volatile boolean flag = false;public void stopThread() {flag = true;
}public void run() {while (!flag) {// do something}
}

原子性

一个操作是否不可中断?

  • i++ 不是原子操作,需要使用 AtomicIntegersynchronized 保证原子性。

有序性

编译器/CPU 可能会指令重排volatile 禁止重排序,synchronized 同样具有顺序性保障。


ReentrantLock vs synchronized

对比项synchronizedReentrantLock
可重入性
公平锁✅ 可选
可中断
读写锁支持✅ 可搭配 ReadWriteLock
性能JDK1.6后优化较好控制更灵活但稍复杂

场景:当需要响应中断超时控制公平锁机制时,优先使用 ReentrantLock


高并发线程安全计数器设计

场景:库存扣减、秒杀扣量

  • 方案:AtomicIntegerLongAdder(高并发推荐)配合 Redis + Lua 保证分布式原子性。
  • 如果涉及分布式系统:
    • Redis 原子扣减 + 库存回滚
    • DB乐观锁(version字段)+ 唯一索引幂等性 + 异步 MQ 补偿机制

2. Spring框架与设计模式

三级缓存解决循环依赖

三级缓存结构:

1. 一级缓存:singletonObjects (成品)
2. 二级缓存:earlySingletonObjects(提前暴露的半成品)
3. 三级缓存:singletonFactories(用于生成早期代理对象)
// 如果构造函数注入(如 @Autowired 构造器)发生循环依赖,无法提前暴露半成品对象,三级缓存失效。

解决方案:推荐使用字段注入或 @PostConstruct 避免构造器注入的循环依赖。


🔹 JDK动态代理 vs CGLIB

特性JDK ProxyCGLIB
是否需要接口
代理机制基于接口,反射生成代理类继承目标类,字节码增强
性能接口多时快复杂类时略慢
Spring选择有接口 → JDK,否则 → CGLIB

责任链模式优惠券参数校验(伪代码)

public interface Handler {void setNext(Handler handler);void handle(Request request);
}public class AmountCheckHandler implements Handler {public void handle(Request req) {if (req.amount < 0) throw new IllegalArgumentException();next.handle(req);}
}

优势:

  • 将每个校验逻辑解耦
  • 动态组合校验链(更灵活)
  • 新增规则无需修改原有代码,符合开放封闭原则

3. MySQL优化与高并发设计

SQL慢查优化流程

  1. 确认慢SQL
  2. EXPLAIN查看执行计划:
    • type:最佳是 const > ref > range > ALL
    • key:是否命中索引
    • rows:预估扫描行数
    • extra:是否出现 Using filesort, Using temporary
  3. 优化手段
    • 添加合适索引
    • 覆盖索引
    • 拆分大表
    • LIMIT 分页优化

分库分表后的跨分片查询

  • 手段:
    • 业务规避
    • 异步聚合(如日志、报表)
    • 中间件支持(如 ShardingSphere 分布式 SQL 解析 + 路由 + 聚合)

唯一索引 + 乐观锁幂等机制

插入前判断记录是否存在(幂等键),或插入失败即跳过。

INSERT INTO coupon_log(user_id, coupon_id, request_id)
VALUES (...) ON DUPLICATE KEY UPDATE ...
  • 乐观锁:基于 version 字段,失败重试
  • 悲观锁:如 SELECT ... FOR UPDATE,加锁范围大,吞吐低
对比乐观锁悲观锁
并发性能
死锁风险存在
应用场景读多写少严格强一致性

4. Redis与高可用架构

为什么用 Lua 实现原子性?

  1. 所有命令作为一个事务性脚本执行
  2. 单线程模型天然避免并发冲突
  3. MULTI/EXEC 不同,Lua 是“不可打断+打包执行”

Redis 脑裂问题与防范

脑裂后主写成功,主挂掉无法同步从节点 → 数据丢失。

防止写入孤立主:

min-slaves-to-write: 2
min-slaves-max-lag: 10

表示只有在有 ≥2 个从节点延迟 <10s 时才允许主节点写入。


布隆过滤器误判率优化

误判 = 说有但其实没有

  • 调整参数:expectedInsertionsfalseProbability
  • 多哈希函数,合理内存分配
  • 将误判项记录到数据库(如灰度机制)
  • 定期重建布隆过滤器

5. 分布式系统与消息中间件

RocketMQ事务消息两阶段提交

  1. Half Message:消息先存储为“准备状态”
  2. 执行本地事务
  3. 事务回查
    • 成功 → Commit
    • 失败 → Rollback
    • 超时 → Broker 定期回查生产者状态

消费端幂等性方案

  • 通过唯一 msg_id/request_id 入库前判断(Redis Set / 去重表 + 唯一索引)
  • 如果高并发瓶颈:
    • Redis 先判断,再异步入库(最终一致)
    • 可设置 TTL 或滑动窗口做清理

MQ堆积延迟排查

  1. 查看消费速率和消费端堆积量
  2. 检查消费者是否:
    • 死循环/业务异常
    • 并发度设置过低
  3. 手段:
    • 扩容消费者
    • 提升消费能力
    • 消息分区优化(或分topic)

6. 短链接系统设计

短链生成算法对比

方法优点缺点
Hash(MD5, SHA)简单、可分布式存在哈希冲突,需重试
Snowflake唯一性强、时间有序不适合短码(太长)
数据库自增简单分布式不方便
base62编码将ID压缩为短字符串需考虑冲突与排序性

推荐组合:Snowflake生成ID + Base62编码


短链唯一性与哈希冲突处理

  1. 哈希后检查数据库是否存在
  2. 存在则重新哈希/加盐或加冲突计数
  3. 记录 原始URL+生成短码 的映射表

QPS 10万级别缓存策略

  1. Redis 做短链跳转缓存(Key: shortCode → URL)
  2. 热点数据加入本地 Caffeine 缓存
  3. 缓存穿透 → 布隆过滤器 + 缓存空值
  4. 异步写DB,日志落盘异步归档

7. 开放性问题

单元测试发现Bug案例

在 Mini-Spring 实现 AOP 时,某个切面注入出现空指针。测试时通过 mock bean 提前暴露出代理对象未生效的问题,进而修复为通过三级缓存暴露代理后的对象。


技术选型分歧如何协调

  1. 收集团队观点 + 论证维度(性能、生态、学习成本)
  2. 快速 POC 小范围验证
  3. 从场景适配角度做最终决策,而非“好恶”
  4. 若有博弈,保留少数意见作为 Plan B,确保应变能力

深入秒杀系统项目技术细节

以下针对“优惠券秒杀系统”的核心技术点进行深度解析与场景化问答:


1. 责任链模式在参数校验中的实现

Q:责任链模式如何保证优惠券创建流程的扩展性?如果新增一个“黑名单用户校验”节点,如何最小化代码改动?

  • 答案
    • 核心实现

      1. 定义统一的校验接口,每个校验器实现该接口并持有下一个节点的引用。
      2. 校验失败时抛出异常,成功则调用链的下一个节点。
      public interface CouponValidator {void validate(CouponRequest request) throws ValidationException;
      }
      public class ParamValidator implements CouponValidator {private CouponValidator next;public void validate(CouponRequest request) {if (request.getAmount() <= 0) throw new ValidationException("金额无效");if (next != null) next.validate(request);}// 设置下一个校验器public void setNext(CouponValidator next) { this.next = next; }
      }
    • 扩展性:新增校验器只需实现CouponValidator接口,并通过setNext插入到责任链中。例如新增BlacklistValidator

      CouponValidator chain = new ParamValidator();
      chain.setNext(new InventoryValidator());
      chain.setNext(new BlacklistValidator()); // 新增节点
    • 优势:无需修改已有校验逻辑,符合开闭原则(OCP)。


2. 执行点记录与断点续发机制

Q:如何设计“执行点记录”机制来支持故障恢复?如果发放优惠券时系统宕机,重启后如何快速恢复?

  • 答案
    • 数据结构设计: 在数据库中记录发放批次的关键信息:

      CREATE TABLE coupon_batch (batch_id VARCHAR(64) PRIMARY KEY,total_count INT,sent_count INT,         -- 已发放数量last_user_id VARCHAR(64) -- 最后处理的用户ID
      );
    • 恢复流程

      1. 系统重启后,查询coupon_batch表获取未完成的批次。
      2. 根据last_user_id从断点处继续遍历用户列表,批量扣减库存并更新sent_count
    • 性能优化

      • 批量处理:每次发放100条优惠券,减少数据库写入压力。
      • 异步日志:通过RocketMQ异步记录发放进度,降低主流程延迟。

3. 幂等性保障方案

Q:如何通过“唯一索引+乐观自旋”实现RocketMQ消费端的幂等性?如果并发极高,自旋重试可能导致CPU飙升,如何优化?

  • 答案
    • 实现逻辑

      1. 消费消息前,尝试插入去重表(唯一索引为消息ID):
      INSERT INTO msg_dedup (msg_id) VALUES ('msg_001') ON DUPLICATE KEY UPDATE msg_id=msg_id;
      1. 若插入成功,继续处理;若触发唯一索引冲突,判定为重复消息,直接丢弃。
    • 自旋优化

      • 限制重试次数:例如最多重试3次,超过则记录日志并人工介入。
      • 退避策略:每次重试前增加等待时间(如指数退避:100ms → 200ms → 400ms)。

4. Redis ZSet在优惠券列表展示中的应用

Q:为什么选择ZSet存储用户已领取的优惠券?如果需支持按过期时间排序,如何设计Score?

  • 答案
    • ZSet优势
      • 天然支持按Score排序(如领取时间),查询时直接使用ZREVRANGE倒序获取。
      • 时间复杂度低:插入和范围查询均为O(log N)。
    • 过期时间排序
      • 将Score设置为优惠券过期时间戳(而非领取时间),查询时按Score范围过滤:

        ZADD user:coupons:1001 1672502400000 "coupon_001"  -- 2023-01-01过期
        ZRANGEBYSCORE user:coupons:1001 1672502400000 +inf  -- 查询未过期优惠券

5. Redis Lua脚本与原子性校验

Q:请写出资格校验的Lua脚本伪代码,并说明为何不直接用Redis事务(MULTI/EXEC)?

  • 答案
    • Lua脚本示例

      -- KEYS[1]: 库存键, KEYS[2]: 已领取用户集合, ARGV[1]: 用户ID
      local stock = tonumber(redis.call('GET', KEYS[1]))
      if stock <= 0 thenreturn 0 -- 库存不足
      end
      if redis.call('SISMEMBER', KEYS[2], ARGV[1]) == 1 thenreturn -1 -- 已领取
      end
      redis.call('DECR', KEYS[1])
      redis.call('SADD', KEYS[2], ARGV[1])
      return 1 -- 领取成功
    • Lua vs 事务

      • 原子性:Lua脚本执行期间不会被其他命令打断,事务中的命令可能被其他客户端插入执行。
      • 灵活性:Lua支持复杂逻辑(如条件判断、循环),事务仅支持简单命令队列。

6. 高并发下缓存穿透与击穿应对

Q:布隆过滤器如何解决缓存穿透?如果误判率较高,如何优化?

  • 答案
    • 布隆过滤器原理
      • 通过多个哈希函数将元素映射到位数组,查询时若任意一位为0,则元素一定不存在。
    • 误判率优化
      1. 增加哈希函数数量:降低冲突概率(但会增加计算开销)。
      2. 扩大位数组容量:减少哈希碰撞。
      3. 兜底策略:缓存空值(key:null)并设置短TTL,拦截重复查询。

7. RocketMQ消息堆积处理

Q:如果消费端处理速度远低于生产端,导致消息大量堆积,如何快速解决?

  • 答案
    • 应急方案
      1. 扩容消费者:增加消费者实例或线程池大小。
      2. 批量消费:调整consumeMessageBatchMaxSize参数,一次处理多条消息。
      3. 降级非核心逻辑:例如先缓存领取记录,异步持久化到数据库。
    • 根本解决
      • 优化消费逻辑:避免同步阻塞操作(如远程调用),改用异步或并行处理。
      • 限流保护:通过Sentinel对消费者限流,避免雪崩。

总结:面试回答技巧

  1. 细节具体化:结合代码、数据结构和流程图说明实现(如“三级缓存解决循环依赖”)。
  2. 场景绑定:强调设计背后的业务需求(如“秒杀场景要求原子性,因此选择Lua脚本”)。
  3. 问题反思:主动提及遇到的挑战(如“初期未考虑构造器注入循环依赖,通过单元测试发现并修复”)。
  4. 性能数据:若有压测结果,可量化说明优化效果(如“引入Redis后,QPS从1k提升至10k”)。

http://www.lryc.cn/news/605544.html

相关文章:

  • Linux移动大量文件命令
  • 递归混合架构(MoR)在医疗领域的发展应用能力探析
  • JAVA后端开发:使用 MapStruct 实现 Java 对象映射
  • 机器学习第二课之逻辑回归(一)LogisticRegression
  • Python与MySQL的关联操作
  • 笔试——Day24
  • 第三章 浏览器
  • Linux的库制作与原理
  • 2025.8-12月 AI相关国内会议
  • Docker 初学者需要了解的几个知识点 (六):docker-compose.yml (ThinkPHP)
  • 向量检索服务的功能特性
  • 企业智脑1.3.1技术升级全面解读:AI笔记引擎如何重塑企业知识管理范式
  • 【科研绘图系列】R语言绘制线性相关性
  • 前端技术栈详解
  • window中qemu使用(安装ubuntu系统)
  • uniapp x swiper/image组件mode=“aspectFit“ 图片有的闪现后黑屏
  • 【机器学习】KNN算法与模型评估调优
  • 8.1-使用向量存储值列表
  • 从“健忘”到“懂我”:构建新一代AI记忆系统
  • 基于MATLAB实现二维云模型
  • Android开发:6种获取屏幕高度和宽度的最佳实践与性能对比
  • 基于MATLAB的GUI来对不同的(彩色或灰色)图像进行图像增强
  • 2025年最新SCI-灰熊增脂优化器(Grizzly Bear Fat Increase, GBF)-附完整Matlab免费代码
  • 007TG洞察:波场TRON上市观察,Web3流量工具的技术解析与应用
  • mysql 日志机制
  • C++_HELLO算法_哈希表的简单实现
  • 反射之专题
  • 将本地项目关联并推送到已有的 GitHub 仓库
  • 第13届蓝桥杯C++青少组中/高级组选拔赛2022年1月22日真题
  • 可计算存储(Computational Storage)与DPU(Data Processing Unit)的技术特点对比及实际应用场景分析