25年10月抖音 Java开发实习生二面

#JAVA##JAVA面经##JAVA内推#

实习期间做过最有成就感或最棘手的需求是啥?

“虽暂无企业实习经历,但在校园二手平台项目中,我主导开发了高并发秒杀模块(类比实习场景):

  • 背景:校园活动期间瞬时流量激增(预估500+并发),需防超卖、保系统稳定
  • 我的职责:方案设计→编码→压测→上线全流程
  • 设计方案
    1️⃣ 流量削峰:RabbitMQ异步队列缓冲请求(设置预热队列防突发)
    2️⃣ 库存控制
    • Redis Lua脚本原子扣减(if stock>0 then decr key end
    • 数据库乐观锁二次校验(version字段)
    3️⃣ 防刷机制:用户维度限流(Guava RateLimiter 3次/秒)+ 验证码
  • 成果:JMeter压测1000并发零超卖,接口P99<200ms
  • 反思:初期忽略Redis缓存击穿,用布隆过滤器+空值缓存补救。最大收获:高并发设计需‘理论+压测+监控’三位一体,任何环节缺失都可能线上事故。”

用 RocketMQ 时,如何保证消息严格有序?

“项目中使用RabbitMQ,但深入研究过RocketMQ有序消息机制:
核心方案

  • 队列级有序:同一业务标识(如订单ID)的消息发送到同一MessageQueue
    producer.send(msg, new MessageQueueSelector() {
        @Override
        public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
            Long orderId = (Long) arg;
            return mqs.get((int)(orderId % mqs.size())); // 按订单ID哈希固定队列
        }
    }, orderId);
    
  • 消费端:单线程消费该队列(避免多线程乱序)
    ⚠️ 踩坑认知
  • 若消费者故障转移,新实例需等待原实例释放队列锁,短暂无序(业务层需幂等兜底)
  • 对比RabbitMQ:RabbitMQ需为每个订单建独立队列(运维成本高),RocketMQ的队列复用更优雅
    态度:技术选型需匹配业务——订单状态流转用有序消息,通知类消息用普通队列提升吞吐。”

看 EXPLAIN 优化慢 SQL,重点关注哪些字段?

“三字段定乾坤:
🔹 type

  • 目标:ref/range(走索引)
  • 警惕:index(全索引扫描)、ALL(全表扫描)→ 立即加索引
    🔹 rows
  • 预估扫描行数,若>总数据10%需警惕(如10万表扫5万行)
  • 结合filtered看有效过滤率
    🔹 Extra
  • Using index:覆盖索引,最优
  • ⚠️ Using filesort:ORDER BY未走索引 → 加联合索引
  • ⚠️ Using temporary:GROUP BY临时表 → 优化分组字段索引
    实战案例:曾优化‘用户订单查询’,将(user_id)单列索引改为(user_id, create_time)typeindexrangerows从8000→15,耗时从1.2s→40ms。”

Linux查日志定位"timeout"行,命令组合?

“高效组合三式:
1️⃣ 实时追踪tail -f app.log | grep --color=auto "timeout"(高亮关键词)
2️⃣ 精准定位grep -n "timeout" app.log | tail -20(显示行号+最后20条)
3️⃣ 上下文关联grep -B 2 -A 3 "timeout" app.log(显示匹配行前后2/3行,快速定位堆栈)
进阶技巧

  • 大日志文件:less +/timeout app.log(less内搜索)
  • 多文件:grep -r "timeout" /var/log/myapp/ --include="*.log"
  • 排除干扰:grep "timeout" app.log | grep -v "connect"(过滤含connect的timeout)”

端口被占用,查进程命令?

“两步精准定位:
1️⃣ 查进程PID
lsof -i :8080(推荐,输出含进程名/用户)
备选netstat -tunlp | grep :8080
2️⃣ 处理进程
kill -9 <PID>(强制终止)
安全操作:先ps -p <PID> -o comm=确认进程名,避免误杀
实战习惯:部署脚本开头加lsof -ti :8080 | xargs kill -9 2>/dev/null,确保端口释放。”

Java 异常体系,运行时异常 vs 受检异常?

核心分界:是否需显式处理(try-catch/throws)
🔹 运行时异常(RuntimeException子类)

  • 例:NullPointerException(空指针)、IllegalArgumentException(参数非法)、ConcurrentModificationException(遍历中修改集合)
  • 特点:程序逻辑错误,应编码避免,通常不捕获
    🔹 受检异常(Exception子类,非RuntimeException)
  • 例:IOException(文件读写)、SQLException(数据库操作)、ClassNotFoundException
  • 特点:外部环境导致,必须处理(如重试/降级)
    项目实践
  • 自定义业务异常继承RuntimeException(如OrderNotFoundException),简化Controller层
  • 受检异常统一转换:MyBatis的SQLException → 封装为ServiceException(含友好提示)”

数据库典型异常及处理?

“两类高频异常实战处理:
⚠️ 唯一键冲突DuplicateKeyException):

  • 场景:用户重复提交注册
  • 处理:
    try { userMapper.insert(user); } 
    catch (DuplicateKeyException e) { 
        throw new BusinessException("手机号已注册"); // 返回前端友好提示
    }
    

⚠️ 连接超时TimeoutException):

  • 场景:DB主从切换瞬间
  • 处理:
    • 配置HikariCP:connection-timeout=3000 + max-lifetime=1800000
    • 全局异常处理器:捕获后返回系统繁忙,请稍后重试 + 企业微信告警
    原则:异常分类处理——用户错误友好提示,系统错误快速告警+降级。”

Dubbo 调用异常与容错设计?

“项目用Spring Cloud,但系统学习过Dubbo容错机制:
⚠️ 常见异常

  • 超时:RpcException(timeout)
  • 服务不可用:NoProviderException
  • 业务异常:自定义异常透传
    🛡️ 容错设计
    1️⃣ 超时控制@Reference(timeout = 3000) + 重试(retries=2,幂等接口)
    2️⃣ 熔断降级:集成Sentinel,QPS>100自动熔断,返回兜底数据
    3️⃣ Mock服务
    @Reference(mock = "return new MockOrderService()")
    OrderService orderService;
    

4️⃣ 监控告警:Dubbo Admin监控调用链,异常率>5%触发告警
认知:微服务容错是‘组合拳’——超时+重试+熔断+监控,缺一不可。”

线程池核心参数作用?

“五参数精准控制:

参数 作用 类比
corePoolSize 核心线程数(常驻) 公司正式员工
maximumPoolSize 最大线程数 正式+临时工上限
workQueue 任务队列(有界/无界) 待办任务池
keepAliveTime 非核心线程空闲存活时间 临时工下班等待时长
RejectedExecutionHandler 拒绝策略 任务溢出处理方案
关键认知
  • 队列选型决定行为:SynchronousQueue(直接提交,适合短任务)、LinkedBlockingQueue(无界,防OOM需慎用)
  • 拒绝策略:CallerRunsPolicy(主线程执行,平滑降级)比AbortPolicy更友好”

如何配置线程池?考虑任务类型吗?

“配置公式 = 任务特性 × 资源约束
🔹 CPU密集型(如加密计算):
corePoolSize = CPU核心数(避免线程切换开销)
:4核机器 → 设4,队列用SynchronousQueue
🔹 IO密集型(如HTTP调用):
corePoolSize = CPU核心数 * 2(线程常阻塞,可多开)
:4核 → 设8,队列用有界队列(ArrayBlockingQueue(100)
🔹 混合型

  • 核心线程=CPU数,最大线程=CPU*2
  • 拒绝策略:ThreadPoolExecutor.CallerRunsPolicy(触发降级)
    项目实践
  • 异步发短信线程池:IO密集 → core=8, max=16, queue=100
  • 压测验证:调整后CPU利用率稳定在70%,无OOM”

setNx 分段锁设计?为何分段?

背景:单商品库存扣减,高并发下单个Redis锁成为瓶颈
分段方案
1️⃣ 分段依据:按商品ID哈希分16段(segment = productId.hashCode() & 15
2️⃣ 锁Key设计lock:product:segment:{segmentId}
3️⃣ 流程

  • 扣减前:SET lock:product:segment:3 nx ex 10(10秒过期)
  • 执行库存操作
  • 释放锁(Lua脚本防误删)
    价值
  • 并发能力提升16倍(16个商品可并行扣减)
  • 避免单点竞争,实测QPS从300→4500
    反思:分段数需压测确定——过少仍竞争,过多增加运维复杂度”

分段锁会遇 ABA 问题吗?如何优化?

关键澄清:Redis分布式锁本身不涉及ABA(锁操作是原子SET/DEL),但业务逻辑(如库存值)可能遇ABA。
项目防护

  • 锁仅控制‘扣减操作串行化’,库存值校验交由数据库乐观锁(version字段)
    UPDATE product SET stock=stock-1, version=version+1 
    WHERE id=? AND version=? AND stock>0
    
  • Redis锁+DB乐观锁双保险,彻底规避ABA
    ⚠️ 若纯Redis方案:需在value存版本号,用Lua脚本比对(但增加复杂度,不推荐)
    认知:分布式场景下,‘锁’解决并发控制,‘版本号’解决数据一致性,二者分工明确。”

(追问)并发涨10倍,锁设计瓶颈?改进思路?

瓶颈分析

  • 分段锁上限=分段数×单段QPS(16×300=4800),10倍并发(5万)必超载
    改进三阶
    1️⃣ 短期:动态扩容分段数(从16→64),需重启服务(有损)
    2️⃣ 中期
    • 引入本地缓存+异步刷盘
      • 本地用ConcurrentHashMap缓存库存(分段锁保护)
      • 定时/定量异步同步DB(减少Redis压力)
    • 限流熔断:Sentinel控制入口流量
      3️⃣ 长期
    • 改用Redisson分布式锁
      ✅ 看门狗自动续期(防业务超时锁失效)
      ✅ 多种锁模式(公平锁、读写锁)
      ✅ 与Spring Boot无缝集成
    • 取舍对比
      方案 优点 缺点
      自研分段锁 轻量、可控 需自维护续期/分段逻辑
      Redisson 功能全、稳定 引入依赖、学习成本

结论:业务初期自研可控,规模扩大后拥抱成熟框架,把精力聚焦业务创新。”

Redis decr 命令使用场景与注意点?

典型场景

  • 库存扣减(配合Lua脚本防超卖)
  • 接口限流(令牌桶:decr token_bucket
  • 倒计时(活动剩余次数)
    ⚠️ 关键注意
    1️⃣ 初始化:必须先SET key 100,否则decr返回(nil)(易踩坑!)
    2️⃣ 负数风险decr可使值<0 → 用Lua脚本校验:
    if redis.call('get', KEYS[1]) > 0 then return redis.call('decr', KEYS[1]) end
    return -1
    

3️⃣ 原子性:单命令原子,但‘判断+扣减’需Lua保证
项目实践:秒杀库存用decr+Lua,压测验证10万次扣减无负数。”

LRU 缓存实现思路?

数据结构组合拳

  • 哈希表(HashMap):O(1)查找节点
  • 双向链表(Linked List):维护访问顺序(头=最新,尾=最旧)
    核心操作
    1️⃣ 访问/更新
    • 哈希表查节点 → 移至链表头部
      2️⃣ 插入
    • 新节点放头部
    • 若超容量:删尾部节点 + 哈希表移除
      3️⃣ 淘汰:直接删尾部
      时间复杂度:所有操作O(1)
      Java实现参考
  • 标准库LinkedHashMap(重写removeEldestEntry
  • 手写:定义Node含key/value/prev/next,维护head/tail指针
    延伸思考
  • 线程安全:高并发场景用ConcurrentHashMap + ReentrantLock分段锁
  • 近似LRU:Redis用随机采样(性能与精度权衡)”

你有什么想了解我们团队、业务方向或者实习安排的吗?

“感谢提问!我有三个具体问题:
1️⃣ 技术成长:团队对实习生是否有‘导师制’?比如每周代码Review、技术分享参与机会?
2️⃣ 业务价值:当前团队最希望实习生补位的技术环节是什么?(如参与核心模块开发/性能优化)
3️⃣ 长期发展:贵司在[提及公司具体技术方向,如:高并发中间件/云原生]有哪些技术规划?实习生能否接触相关项目?
补充:我渴望的不仅是完成任务,更是理解业务逻辑、参与技术决策,在实战中成长为能独当一面的工程师。”

#JAVA##面经##Java面经#

本专栏在精不在多,内容分为八股文、大厂真实面经,面试通过后将offer和面试题私发给我,可退还专栏的收益部分费用。欢迎大家共建专栏

全部评论

相关推荐

Hao_Miao:佬那你去的话还请假吗,虽然不是一个校区但我问我们导员说不给批的,一个月以上得办休学,也是逆天完了。直接跑的话会不会被处分然后拽回来
点赞 评论 收藏
分享
刚刷到字节跳动官方发的消息,确实被这波阵仗吓了一跳。在大家还在纠结今年行情是不是又“寒冬”的时候,字节直接甩出了史上规模最大的转正实习计划——ByteIntern。咱们直接看几个最硬的数,别被花里胡哨的宣传词绕晕了。首先是“量大”。全球招7000多人是什么概念?这几乎是把很多中型互联网公司的总人数都给招进来了。最关键的是,这次的资源分配非常精准:研发岗给了4800多个Offer,占比直接超过六成。说白了,字节今年还是要死磕技术,尤其是产品和AI领域,这对于咱们写代码的同学来说,绝对是今年最厚的一块肥肉。其次是大家最关心的“转正率”。官方直接白纸黑字写了:整体转正率超过50%。这意味着只要你进去了,不划水、正常干,每两个人里就有一个能直接拿校招Offer。对于2027届(2026年9月到2027年8月毕业)的同学来说,这不仅是实习,这简直就是通往大厂的快捷通道。不过,我也得泼盆冷水。坑位多,不代表门槛低。字节的实习面试出了名的爱考算法和工程实操,尤其是今年重点倾斜AI方向,如果你简历里有和AI相关的项目,优势还是有的。而且,转正率50%也意味着剩下那50%的人是陪跑的,进去之后的考核压力肯定不小。一句话总结:&nbsp;27届的兄弟们,别犹豫了。今年字节这是铁了心要抢提前批的人才,现在投递就是占坑。与其等到明年秋招去千军万马挤独木桥,不如现在进去先占个工位,把转正名额攥在手里。
哪些公司开暑期实习了?
点赞 评论 收藏
分享
评论
2
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务