观妙科技 - Java开发 二面 面经

1. 上次一面聊了你的项目,能再深入说说项目中遇到的最大挑战吗?

最大的挑战是处理秒杀场景的高并发问题。

当时模拟了一个促销活动,瞬间有几千个请求抢购商品。最初的实现是直接查数据库库存,然后扣减,结果出现了超卖问题,而且数据库压力特别大,响应很慢。

我分析后发现主要有三个问题:数据库成为瓶颈,库存扣减不是原子操作,没有做流量控制。

解决方案是多层优化。首先把库存预热到Redis,用Lua脚本保证扣减的原子性。Lua脚本先判断库存是否充足,充足才扣减,整个过程是原子的。然后在网关层用Sentinel做限流,超过阈值直接拒绝。订单创建改成异步的,扣完库存就返回,通过RabbitMQ慢慢处理订单。

还做了一些细节优化,比如前端按钮防重复点击,Nginx做负载均衡,数据库读写分离。通过JMeter压测,优化后QPS从几百提升到三千多,没有出现超卖。

这个过程让我理解了高并发场景下要从多个层面优化,单点优化效果有限。也学会了用工具定位瓶颈,针对性解决问题。

2. 说说ConcurrentHashMap的实现原理,和HashMap有什么区别?

ConcurrentHashMap是线程安全的HashMap,但实现机制不同。

JDK 1.7用分段锁,把数据分成多个Segment,每个Segment是一个小的HashMap,继承自ReentrantLock。读操作不加锁,写操作只锁当前Segment,理论上支持16个线程并发写。

JDK 1.8取消了Segment,改用CAS加synchronized实现更细粒度的锁。数据结构和HashMap一样,是数组加链表加红黑树。锁的粒度是数组的每个位置,只有hash冲突时才用synchronized锁住链表或红黑树的头节点。使用CAS进行无锁的插入和更新,性能更好。

和HashMap的区别:

线程安全性,HashMap不是线程安全的,ConcurrentHashMap是。如果多线程用HashMap会出现数据丢失、死循环等问题。

null值,HashMap允许一个null key和多个null value,ConcurrentHashMap都不允许,会抛异常。

性能,单线程HashMap更快,多线程ConcurrentHashMap更快。

迭代器,HashMap的迭代器是fail-fast的,ConcurrentHashMap是弱一致性的,不会抛ConcurrentModificationException。

实际使用中,单线程用HashMap,多线程用ConcurrentHashMap。不要用Hashtable,性能差而且过时了。

3. JVM的垃圾回收机制了解吗?有哪些垃圾回收器?

JVM垃圾回收主要针对堆内存。

判断对象是否可回收用可达性分析算法,从GC Roots开始遍历,能到达的对象是存活的,不能到达的是垃圾。GC Roots包括虚拟机栈中的引用、静态变量、常量、本地方法栈的引用等。

垃圾回收算法有几种:

标记-清除,标记存活对象,清除未标记的,简单但会产生内存碎片。

标记-复制,把内存分两块,每次只用一块,垃圾回收时把存活对象复制到另一块,然后清空这一块。不会有碎片但浪费空间,适合新生代。

标记-整理,标记存活对象,然后移动到一端,清理边界外的内存。不会有碎片也不浪费空间,但移动对象有开销,适合老年代。

常见的垃圾回收器:

Serial,单线程,适合客户端应用。Parallel,多线程,吞吐量优先,适合后台计算。CMS,并发标记清除,停顿时间短,但会产生碎片。G1,分区回收,可预测停顿时间,JDK 9后的默认回收器,适合大内存应用。ZGC和Shenandoah,低延迟回收器,停顿时间在10ms以内,适合对延迟敏感的应用。

实际使用中,根据应用特点选择回收器。吞吐量优先用Parallel,延迟敏感用G1或ZGC。通过JVM参数调整堆大小、新生代比例等,使用工具分析GC日志优化性能。

4. 分布式事务有哪些解决方案?你项目中用过吗?

分布式事务是跨多个数据库或服务的事务,保证一致性比较复杂。

常见解决方案:

2PC两阶段提交,协调者先询问所有参与者能否提交,都同意再发提交命令。强一致性但性能差,有阻塞和单点问题,实际很少用。

TCC,业务层面的两阶段提交。Try预留资源,Confirm确认提交,Cancel回滚。需要业务代码实现三个接口,开发成本高但性能好,适合对一致性要求高的场景。

本地消息表,在本地数据库记录消息,事务提交后发送MQ,消费者处理后更新状态。定时任务扫描未发送的消息重试。实现简单,保证最终一致性。

消息事务,RocketMQ支持事务消息。发送半消息,执行本地事务,根据结果提交或回滚消息。消费者处理消息,失败则重试。

Saga模式,把长事务拆分为多个本地短事务,每个事务有对应的补偿操作。某步失败就执行之前所有步骤的补偿。适合长流程业务。

我项目中用的是消息队列保证最终一致性。比如下单后扣库存、扣积分、发通知,这些操作通过Rabb

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Java面试圣经 文章被收录于专栏

Java面试圣经,带你练透java圣经

全部评论
我当时面java实习生二面真没这么难 基本围绕个人生活和一部分项目问了四十来分钟
2 回复 分享
发布于 03-04 14:43 吉林
二面一小时,挂了
2 回复 分享
发布于 03-03 17:02 湖北
27届实习机会或看我住业 https://careers.pddglobalhr.com/campus/intern?t=4OmKPVeX9a
点赞 回复 分享
发布于 03-11 14:50 上海
这要是真能背下来,我服
点赞 回复 分享
发布于 03-04 13:12 黑龙江
沾点喜气,二面凉了?我这菜鸡哭唧唧
点赞 回复 分享
发布于 03-03 19:10 四川
倒反天罡,反问拷打起面试官了
点赞 回复 分享
发布于 03-03 17:40 河南
点赞 回复 分享
发布于 03-02 11:47 湖北

相关推荐

3月中旬面的一家一面:1. 实习中有没有遇到多线程的问题2. 创建线程的几种方式3. 线程池的拒绝策略4. mysql索引失效的几种情况5. 索引失效该怎么进行查看,有哪些字段需要关注6. 讲一下HashMap7. 对ai的认识和理解二面:1. 简单聊一下你的最熟悉的一个项目,然后那个比较有亮点的一个项目,然后展开说一下他那你在这里面是做了哪些事儿,然后有哪些东西比较有挑战。2. 检测agent死循环是代码里面写死的还是让上下文自动识别有死循环的3. 记忆的一个存储方式是什么4. 持久化的过程中,所有的数据是通过什么来进行获取的5. 实现一个功能,超过多少上下文再对当前会话的上下文进行总结归纳进行压缩6. 你是怎么理解他的那个对话模式下的一个记忆保存?比方说我跟那个大模型进行我调用大模型的时候,我每次对话,为什么我说一句话他会有记忆的?7. ai调用mcp的stdio和sse两种方式有啥区别8. 讲一下你的科研系统9. 单点登录系统有新用户注册了,你们这边如何实现自动注册该用户10. 如果有用户在今天离职了,你们的系统凌晨才进行更新,那这样数据不就有一个滞后性,这个如何解决11. 如果学校那边的有用户离职了,你们这边如何实现对本系统的用户数据的一个清理12. 那状态机这块当时为什么会使用这个spring的这个状态机感觉不是特别好用13. 这个状态机假设它是一个所有的状态流转,它会存在一个问题,就是如果说是在多台机器上面,它这个状态会有问题吗?14. 那你还主导了一个并主导设计并实现了一个研究成果量化积分模块积分模块这块东西是主要是做什么?
查看21道真题和解析
点赞 评论 收藏
分享
评论
9
26
分享

创作者周榜

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