#JAVA##JAVA面经##JAVA内推#
单例模式:双重检查锁的单例你写过吗?能说说实现思路吗?volatile在这里起啥关键作用?
“写过并深度理解。实现思路:
1️⃣ 私有构造方法 + 静态volatile实例(初始null)
2️⃣ getInstance()中:
- 第一重检查:if (instance == null) 进入同步块
- synchronized加锁
- 第二重检查:if (instance == null) 才创建实例
volatile关键作用:
⚠️ 禁止指令重排序:JVM可能将new Singleton()重排为「分配内存→赋值引用→初始化对象」,导致其他线程拿到未初始化的instance
✅ volatile通过内存屏障保证:- 写操作:创建对象完成后才写入instance
- 读操作:读取instance前刷新工作内存
项目实践:在Redis连接池、ID生成器等工具类中使用,经JMH压测验证线程安全。”
HashMap细节:JDK8里链表长度到8才转红黑树,这个“8”是咋定的?多线程下HashMap扩容容易出问题,项目里怎么规避的?
"‘8’的由来:
- 基于泊松分布:链表长度≥8的概率≈0.00000006(百万分之一)
- 阈值7(TREEIFY_THRESHOLD-1):留缓冲避免频繁树化/链化
- 红黑树节点占用空间≈链表2倍,仅高频冲突时启用
多线程规避三板斧:
🔹 首选:ConcurrentHashMap(分段锁/CAS,项目中缓存、计数器全用它)
🔹 写少读多:Collections.synchronizedMap+ 外层业务锁
🔹 彻底规避:
- 线程局部变量(ThreadLocal)
- 不可变Map(
Map.of())
血泪教训:曾用HashMap存配置缓存,压测时出现ConcurrentModificationException,后全量替换为ConcurrentHashMap并加注释警示。”
Spring生命周期:Bean从创建到销毁经历了哪些关键步骤?@PostConstruct和InitializingBean谁先执行?你项目里在这些阶段做过啥操作?
"生命周期七步:
实例化 → 属性注入 → Aware接口回调 → @PostConstruct → InitializingBean.afterPropertiesSet → 自定义init-method → 使用中 → DisposableBean.destroy → @PreDestroy
✅ 执行顺序:@PostConstruct先于afterPropertiesSet(JSR-250规范优先级更高)
项目实战:
@PostConstruct:预热Redis缓存(加载热点商品数据)afterPropertiesSet:校验外部配置(如MQ连接参数)@PreDestroy:优雅关闭线程池(executor.shutdown())
认知:初始化逻辑按‘轻量→重量’分层,避免启动阻塞。”
GC排查实战:线上突然Full GC频繁,你会怎么一步步查?
“五步排查法:
1️⃣ 实时监控:
jstat -gcutil <pid> 1000:看YGC/FGC频率、老年代占比- Arthas
dashboard:线程数、内存波动
2️⃣ 堆转储:jmap -dump:format=b,file=heap.hprof <pid>(加-XX:+HeapDumpOnOutOfMemoryError预防)
3️⃣ 分析工具:- MAT:查‘支配树’找内存泄漏对象(如静态Map缓存未清理)
- Arthas
heapdump+ognl动态查对象
4️⃣ 根因定位:- 案例:MAT发现
ConcurrentHashMap持有10万+无效Session → 源于未设过期时间
5️⃣ 修复验证:- 加LRU淘汰策略 + 定时清理任务
- 压测验证GC频率回归正常
心得:监控前置(Prometheus+AlertManager)比事后排查更重要。”
高并发设计:设计秒杀防超卖,你会怎么层层设计?
“四层防护体系:
🛡️ 前端层:按钮置灰+倒计时(防重复点击)
🛡️ 网关层:
- 限流:Sentinel集群流控(QPS=1000)
- 验证码:滑块验证(过滤机器人)
🛡️ 服务层:- 缓存预热:Redis预减库存(
DECR stock+ Lua脚本原子操作)- 队列削峰:RabbitMQ缓冲请求(消费者匀速处理)
🛡️ 数据层:- 数据库:乐观锁(
UPDATE stock SET num=num-1 WHERE id=100 AND num>0)- 对账补偿:定时任务校验库存一致性
参考方案:结合阿里《秒杀系统设计》+ 自研压测验证,实测支撑5000QPS无超卖。”
算法思路:反转链表的逻辑能口头捋一捋吗?
“迭代法(推荐):
1️⃣ 三指针:prev=null, curr=head, next
2️⃣ 循环:
- next = curr
全部评论
(1) 回帖