辛集市网站建设_网站建设公司_前端工程师_seo优化
2026/1/14 16:13:04 网站建设 项目流程

Java实习模拟面试|上海禾赛科技后端实习一面面经:高并发数据去重、事务与MQ一致性、反射争议与缓存选型深度解析

关键词:禾赛科技后端实习|Java高并发|消息可靠性|事务传播行为|Redis vs 本地缓存|反射破坏封装?|线程池调优|CSDN面经


在准备2025届暑期实习的过程中,我针对上海禾赛科技(Hesai Tech)的Java后端岗位进行了一场高度仿真的模拟一面。作为一家专注于激光雷达与智能感知系统的硬科技公司,其后端系统对数据可靠性、高并发处理、跨服务通信一致性有极高要求。

本文以真实对话形式还原整场60分钟面试,采用“面试官提问 + 候选人口头回答 + 连环追问”结构,覆盖项目深挖、并发基础、Spring事务、缓存选型、反射哲学、MQ可靠性设计六大核心模块,助你精准把握硬科技公司对实习生的技术期待!


1. 拷打上一份实习:如何保证数据可靠、去重、高并发?

面试官提问:你在上一段实习中提到处理大量传感器上报数据,怎么保证数据不丢、不重、高并发写入


我们面对的是每秒数万条设备上报的原始点云元数据,核心挑战是幂等写入 + 高吞吐 + 低延迟。我们的方案分三层:

(1)去重机制

  • 每条数据携带全局唯一trace_id(由设备生成,符合UUIDv7规范)。
  • 写入前先查Redis布隆过滤器(Bloom Filter)
    • 若不存在 → 放行;
    • 若存在 → 再查 MySQL 唯一索引(trace_id)做二次校验,避免布隆误判。
  • 布隆过滤器定期滚动(如每小时重建),防止内存无限增长。

(2)高并发写入

  • 使用ShardingSphere 分库分表,按device_id % 16分片,分散写压力。
  • 批量插入:Kafka消费者攒批(1000条/批 or 100ms超时),用INSERT ... ON DUPLICATE KEY UPDATE实现幂等。

(3)可靠性保障

  • Kafka 生产者开启acks=all+ 幂等(enable.idempotence=true);
  • 消费者手动提交 offset,确保“处理成功才提交”。

追问:如果 Redis 宕机,布隆过滤器失效,会不会导致大量重复请求打到 DB?


会!所以我们做了降级策略

  • 当 Redis 不可用时,自动跳过布隆过滤,直接走 MySQL 唯一索引
  • 同时触发告警,运维介入;
  • 虽然 QPS 会短暂下降(因 DB 唯一索引冲突回滚),但数据正确性不受影响

2. List 和 Set 的区别?

面试官提问:说说ListSet的核心区别?

特性ListSet
有序性有序(按插入顺序)无序(除 LinkedHashSet)
重复元素允许不允许
典型实现ArrayList, LinkedListHashSet, TreeSet, LinkedHashSet
底层结构ArrayList: 动态数组;LinkedList: 双向链表HashSet: HashMap(key-only);TreeSet: 红黑树

使用场景

  • List:需要保留插入顺序、允许重复(如日志记录、任务队列);
  • Set:去重、快速查找(如用户ID集合、权限校验)。

3. 如何实现线程?

面试官提问:Java 中创建线程有哪几种方式?


主要有三种:

  1. 继承Thread(不推荐,Java单继承限制)
  2. 实现Runnable接口(常用,解耦任务与线程)
  3. 实现Callable<V>+FutureTask(支持返回值和异常)

现代最佳实践永远不要手动 new Thread(),而是使用线程池(如ExecutorsThreadPoolExecutor),避免资源耗尽。


4. 线程池核心参数 & 如何设置?

面试官提问:线程池有哪些核心参数?怎么合理设置?


ThreadPoolExecutor七大参数:

newThreadPoolExecutor(intcorePoolSize,// 核心线程数(常驻)intmaximumPoolSize,// 最大线程数longkeepAliveTime,// 空闲线程超时时间TimeUnitunit,BlockingQueue<Runnable>workQueue,// 任务队列ThreadFactorythreadFactory,RejectedExecutionHandlerhandler// 拒绝策略);

如何设置?看任务类型!

  • CPU密集型(如计算):core = CPU核数 + 1
  • IO密集型(如DB/网络):core = 2 * CPU核数(经验值)

队列选择

  • 高吞吐:LinkedBlockingQueue(无界,慎用!可能OOM)
  • 控制资源:ArrayBlockingQueue(有界,配合拒绝策略)

拒绝策略:生产环境建议自定义,记录日志 + 告警,而非直接抛异常。


5–6. Spring 事务方式 & 传播行为

面试官提问:Spring 有哪两种事务管理方式?事务传播行为有哪些?

两种方式:

  1. 编程式事务TransactionTemplate手动控制(灵活但冗余)
  2. 声明式事务@Transactional注解(主流,AOP实现)

七种传播行为(重点记前3个):

行为说明
REQUIRED(默认)有事务则加入,无则新建
REQUIRES_NEW挂起当前事务,新建独立事务
SUPPORTS有事务则用,无则非事务执行
NOT_SUPPORTED挂起事务,非事务执行
MANDATORY必须在事务中,否则抛异常
NEVER不能在事务中,否则抛异常
NESTED嵌套事务(Savepoint回滚)

典型场景

  • 日志记录用REQUIRES_NEW,避免主业务回滚导致日志丢失;
  • 批量处理用NESTED,单条失败不影响整体。

7. Redis 与本地缓存的优点对比?

面试官提问:Redis 和 Caffeine/Guava 这类本地缓存各有什么优劣?

维度Redis(分布式缓存)本地缓存(Caffeine)
访问速度~1ms(网络开销)~100ns(内存直取)
一致性强(可集群同步)弱(各节点独立)
容量GB~TB级受限于单机内存
高可用主从+哨兵/Cluster无(进程挂即丢)
适用场景跨服务共享数据(如用户会话)高频读、低变更数据(如配置、字典)

最佳实践多级缓存
先查本地缓存 → 未命中查 Redis → 再查 DB,并异步回填两级缓存。


8. Spring 预先加载的注解和顺序?

面试官提问:Spring Bean 初始化时,哪些注解控制加载顺序?


关键注解及其执行顺序:

  1. 构造函数注入
  2. @Autowired/@Resource字段/方法注入
  3. @PostConstruct(初始化方法)
  4. InitializingBean.afterPropertiesSet()
  5. init-method(XML或@Bean指定)

注意@PostConstruct是 JSR-250 标准,比 Spring 特有接口更通用。


9–10. 如何访问私有方法?反射破坏封装了吗?

面试官提问:怎么调用一个类的私有方法?这是否破坏了面向对象的封装性?

访问私有方法:

Methodmethod=clazz.getDeclaredMethod("privateMethod");method.setAccessible(true);// 绕过访问检查method.invoke(obj);

是否破坏封装?

我的观点工具无罪,滥用有害

  • 合理场景:单元测试(Mock私有逻辑)、框架开发(如Spring AOP代理);
  • 风险:破坏类的不变性(invariants),导致难以维护;
  • 设计原则:优先通过公有接口暴露能力,若必须用反射,应加安全校验(如模块权限控制)。

JDK9+ 模块系统(JPMS)已限制跨模块反射,进一步强化封装。


11. Java 常见的锁实现?

面试官提问:Java 中有哪些常见的锁?

锁类型实现特点
synchronizedJVM内置(Monitor)自动加解锁,不可中断
ReentrantLockAQS(AbstractQueuedSynchronizer)可中断、超时、公平锁
ReadWriteLockReentrantReadWriteLock读写分离,提升并发
StampedLock乐观读(tryOptimisticRead)性能更高,但复杂
分布式锁Redis(SETNX)、ZooKeeper跨JVM协调

选型建议

  • 简单同步 →synchronized(JVM优化后性能接近ReentrantLock);
  • 需要超时/公平 →ReentrantLock
  • 读多写少 →ReadWriteLock

12. 并发多线程需要注意的问题?

面试官提问:写多线程程序要注意哪些坑?


五大核心问题:

  1. 可见性:用volatile或锁保证主存同步;
  2. 原子性:复合操作(如 i++)需加锁或用AtomicInteger
  3. 有序性:指令重排序可能导致逻辑错误(volatile/锁禁止重排);
  4. 死锁:避免嵌套锁、按固定顺序加锁;
  5. 线程安全类误用:如SimpleDateFormat非线程安全,应改用DateTimeFormatter

调试工具jstack查死锁,Arthastrace 方法耗时。


13. MQ 消息发生在事务前还是事务后合适?

面试官提问:在数据库事务中,MQ 消息应该在 commit 前发还是后发?


绝对不能在 commit 前发!否则可能:

  • 事务回滚 → 消息已发 →下游收到无效消息(数据不一致)

正确做法(最终一致性):

  1. 事务内:写 DB + 写消息表(与业务表同库同事务)
  2. 事务外:异步扫描消息表,发送 MQ,成功后删除记录

进阶方案

  • 本地消息表(如上)
  • RocketMQ 事务消息(半消息 + 回查)
  • Seata TCC(Try-Confirm-Cancel)

14. 场景题:如何可靠推送消息给外部公司服务?

面试官提问:你们要通过 MQ 推送数据给合作公司的 HTTP 服务,如何保证不丢失、不重复、顺序正确


这是一个典型的跨系统最终一致性问题,我的方案如下:

(1)消息生产端(我们)

  • 使用持久化队列(如 RocketMQ/Kafka + 副本)
  • 开启生产者幂等 + ACK=all
  • 消息体包含:msg_id(全局唯一)、biz_seq(业务序号)、payload

(2)消息消费端(我们)→ 外部HTTP

  • 可靠投递
    • 消费后先存 DB(状态=“待发送”)
    • 调用外部 HTTP 接口(带 retry + 超时)
    • 成功 → 更新状态=“已发送”;失败 → 加入重试队列(指数退避)
  • 幂等接收(要求对方支持):
    • 请求头带X-Request-ID: msg_id
    • 对方基于msg_id去重

(3)兜底机制

  • 对账系统:每天比对我们 DB 与对方回执日志,修复差异;
  • 人工干预入口:支持重推单条消息。

关键原则我们只保证“尽力送达”,最终一致性靠双方协同


总结:禾赛科技一面考察重点

模块考察意图复习建议
项目深挖工程落地能力、故障意识准备“问题-方案-结果”案例
并发基础线程、锁、线程池动手写 Demo 验证
Spring 事务分布式系统一致性基石理解传播行为 + 事务边界
缓存选型性能 vs 一致性权衡对比 Redis/Caffeine/Ehcache
MQ 可靠性跨系统协作核心掌握本地消息表、事务消息

硬科技公司特点:不追求炫技,但极度重视系统稳定性、数据准确性、可维护性。回答时多提“监控”、“降级”、“对账”、“幂等”等关键词!


觉得这篇面经有帮助?欢迎点赞 + 收藏 + 关注!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询