美团JAVA面经,贼麻烦的面试
《面试题目》
- 布隆过滤器;缓存空结果;参数校验。
- 延迟双删;基于binlog监听;设置合理缓存过期时间兜底。
- RDB。AOF
- RDB更快。
- 单线程处理命令 + I/O多路复用。单线程避免锁竞争;I/O多路复用使单线程高效管理大量连接,仅当socket就绪时处理IO。
- 读未提交、读已提交、可重复读、串行化
- 可重复读。解决脏读、不可重复读;通过MVCC和间隙锁减少幻读发生。
- 默认 B+树。
- 红黑树的二叉搜索树,树高较高;范围查询需中序遍历效率低;节点存储利用率较低。 B+树的更矮胖;叶节点链表结构使范围查询/全表扫描极高效;节点存储更多键。
- 使用二级索引查询时,若所需列不在该索引中,需根据索引中存储的主键值,回到聚集索引 树中查找完整行数据。额外磁盘IO是主要性能损耗。
- 查询:连接器、查询缓存、分析器、优化器、执行器、返回结果。更新:额外涉及事务开启、写undo log、执行器调引擎修改内存数据、写redo log、写binlog、提交事务。
- 更新:写undo/redo,改内存,写binlog,提交redo;两阶段提交。
- 继承Thread类,实现Runnable接口,实现Callable接口,使用线程池提交任务。
- 核心线程数、最大线程数、存活时间、时间单位、工作队列、线程工厂、拒绝策略。
- CountDownLatch要求子线程主动存结果到共享集合后countDown(),主线程await()阻塞等待;CyclicBarrier由线程在await()前存结果,最后到达的线程触发汇总;而线程池通过主线程收集Future并调用get()阻塞获取结果。
- start() 启动新线程,run()普通方法调用。
- 数组+ 链表/红黑树。
- 非线程安全。
- JDK8 ConcurrentHashMap:改用 synchronized 锁单个桶 + CAS + volatile,替代 JDK7 分段锁,并发度更高。
- MQ 消息可靠:依赖生产者可靠投递(含重试)、Broker 持久化与高可用、消费者手动 ACK 与幂等处理三方协同保障。
- 消费者幂等性:通过唯一约束(如 DB/REDIS 记录消息 ID)防止重复处理,确保多次消费结果一致
- 用过什么java框架?
- 微服务之间怎么相互调用
- RPC怎么从A服务调用B服务
- RabbitMQ怎么调用其他服务
《参考解析》
-
MySQL深度:MySQL InnoDB使用B+树索引,支持ACID事务。关键知识点:聚簇索引(主键索引)叶节点存完整行数据;辅助索引叶节点存主键值(需回表);MVCC通过undo log版本链+ReadView实现多版本并发控制,解决脏读/不可重复读;事务隔离级别从低到高:读未提交→读已提交→可重复读(默认)→串行化。
-
Redis核心:Redis常用数据结构:String/Hash/List/Set/ZSet。持久化:RDB(定期快照,恢复快,数据可能丢失)和AOF(追加日志,数据安全,文件大)。缓存穿透用布隆过滤器;缓存雪崩加随机过期时间+多级缓存;缓存击穿用互斥锁或逻辑过期。分布式锁用SET key value NX PX + Lua脚本保证原子释放。
-
Java并发:Java并发:synchronized关键字(偏向锁→轻量级锁→重量级锁升级);ReentrantLock(可重入、可中断、公平锁);volatile(内存可见性+禁止指令重排,不保证原子性);CAS(Compare-And-Swap,无锁乐观并发);ThreadLocal(线程本地变量,WeakReference,注意内存泄漏)。线程池核心参数:corePoolSize/maximumPoolSize/keepAliveTime/workQueue/handler。
-
消息队列:消息队列解决异步解耦、流量削峰。消息可靠性:生产者confirm确认;Broker持久化;消费者手动ACK。幂等性:消费端通过唯一ID+Redis或DB乐观锁实现。顺序消息:同一业务Key路由到同一分区/Queue,单线程消费。消息积压:扩消费者+增加分区+临时跳过非关键消息。