当前位置: 首页 > news >正文

【面试】 Java中级开发工程师面试精选:深度问题与实战解析..

文章目录

        • 🔥 问题1:HashMap与ConcurrentHashMap的线程安全差异
        • ⚡ 场景题1:分布式锁下的资源竞争
        • 💡 问题2:JVM内存模型与OOM实战
        • 🔧 场景题2:线程池拒绝策略设计
      • ✅ 总结考察点

🔥 问题1:HashMap与ConcurrentHashMap的线程安全差异

问题
在多线程环境下,HashMapConcurrentHashMap的线程安全性有何本质区别?请结合缓存雪崩场景说明如何选择。

答案

  • 本质区别
    HashMap非线程安全,多线程并发put可能导致链表成环(JDK1.7)或数据覆盖(JDK1.8);
    ConcurrentHashMap通过 分段锁(JDK1.7)或 CAS + synchronized(JDK1.8)保证线程安全,锁粒度细化到桶级别。
  • 缓存雪崩场景
    假设高并发查询商品库存,缓存失效后大量请求穿透到数据库。
    选择ConcurrentHashMap
    private final ConcurrentHashMap<String, AtomicInteger> stockCache = new ConcurrentHashMap<>();  public void deductStock(String productId) {  stockCache.compute(productId, (k, v) -> {  if (v == null) v = new AtomicInteger(loadFromDB(k)); // 惰性加载  return v.decrementAndGet() >= 0 ? v : null; // 原子减库存  });  
    }  
    
    优势compute()方法保证单键操作的原子性,避免超卖;分段锁支持高并发更新。

⚡ 场景题1:分布式锁下的资源竞争

问题
某支付系统需保证同用户10秒内仅允许1次提现操作。若用Redis分布式锁实现,如何解决锁失效时间与业务执行时间的不确定性?

答案
方案锁续期(WatchDog) + 唯一令牌

public boolean tryWithdraw(String userId, double amount) {  String lockKey = "lock:withdraw:" + userId;  String token = UUID.randomUUID().toString(); // 唯一标识  try {  // 尝试加锁(SET lockKey token NX PX 10000)  if (redis.set(lockKey, token, "NX", "PX", 10000)) {  // 启动WatchDog后台线程续期锁(每3秒续期10秒)  startWatchDog(lockKey, token);  if (checkWithdrawLimit(userId)) { // 业务逻辑  executeWithdraw(userId, amount);  return true;  }  }  return false;  } finally {  // 释放锁时验证token(Lua脚本保证原子性)  String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";  redis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(token));  }  
}  

关键点

  1. 唯一令牌:避免误删其他线程的锁;
  2. 锁续期:防止业务未执行完锁过期;
  3. Lua原子解锁:保证判断与删除的原子性。

💡 问题2:JVM内存模型与OOM实战

问题
线上服务频繁触发OutOfMemoryError: Metaspace,如何定位?列举3种优化策略。

答案
定位步骤

  1. jcmd <pid> VM.flags 检查Metaspace配置(-XX:MaxMetaspaceSize=256m);
  2. jstat -gcmetacapacity <pid> 观察元空间使用趋势;
  3. MAT工具分析ClassLoader泄露(如动态生成类未卸载)。

优化策略

  1. 限制动态代理类:减少CGLib/ASM生成的类;
  2. 配置回收阈值-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m
  3. 重启策略:通过容器化定时重启实例释放元空间。

🔧 场景题2:线程池拒绝策略设计

问题
订单系统需异步处理10万+/日的物流推送,线程池配置为core=5, max=20, queue=100
突发流量下队列满且线程数达max,如何自定义拒绝策略保证关键订单不丢失

答案
方案降级写入MQ + 告警

ThreadPoolExecutor executor = new ThreadPoolExecutor(  5, 20, 30, TimeUnit.SECONDS,  new ArrayBlockingQueue<>(100),  new CustomRejectedExecutionHandler() // 自定义拒绝策略  
);  // 自定义拒绝策略  
static class CustomRejectedExecutionHandler implements RejectedExecutionHandler {  @Override  public void rejectedExecution(Runnable task, ThreadPoolExecutor executor) {  if (task instanceof LogisticsTask) {  LogisticsTask logisticsTask = (LogisticsTask) task;  if (logisticsTask.isHighPriority()) {  // 关键订单写入RabbitMQ/Kafka  mqClient.send("ORDER_FALLBACK_QUEUE", logisticsTask);  } else {  log.warn("丢弃普通订单: {}", logisticsTask.getOrderId());  }  triggerAlert(); // 触发扩容告警  }  }  
}  

效果

  • 关键订单通过MQ异步补偿;
  • 普通订单丢弃避免拖垮服务;
  • 告警触发K8s自动扩容Pod。

✅ 总结考察点

  1. 并发编程:线程安全容器、锁机制、原子操作;
  2. JVM调优:内存模型、OOM排查、GC策略;
  3. 分布式设计:分布式锁、降级策略、异步补偿;
  4. 框架实战:线程池参数化设计、资源竞争解决方案。

提示:实际面试中可延伸追问细节(如synchronized锁升级过程、ThreadLocal内存泄露案例),验证候选人知识深度。

http://www.dtcms.com/a/507383.html

相关文章:

  • 投资理财学习笔记
  • 在openEuler 24.03 (LTS) 上配置 Python 开发环境教程
  • Claude Skill 编写最佳实践
  • 4D毫米波雷达MIMO天线阵列布局设计
  • Agent框架
  • 网站建设 岗位职责 智联设计wordpress页面模板下载地址
  • 网站建设专项检查中国建筑招聘信息
  • ADAPT论文阅读
  • 具身智能论文阅读:Nav-R1: Reasoning and Navigation in Embodied Scenes
  • MySQL JDBC Driver URL参数配置规范
  • python基础知识2
  • 如何做织梦手机网站网站被墙301怎么做
  • 网页网站原型图占位符怎么做凡客诚品为什么失败
  • 【初识数据库】索引
  • Linux服务器编程实践59-管道通信:pipe函数创建匿名管道的方法与使用
  • 容器化安装新玩法
  • JVM内存分配机制
  • 企业网站的基本内容有哪些首页排名关键词优化
  • Qt C++ 调用 YOLO / SAM2的方案
  • AD导出FPGA管脚的方法
  • 邯郸做网站的公司郴州建设网站公司
  • 基于 ComfyUI + Wan2.2 animate实现 AI 视频人物换衣:完整工作流解析与资源整合(附一键包)
  • wdaaw
  • 做个企业网网站怎么做西安注册公司虚拟地址
  • [Java数据结构与算法]详解排序算法
  • 工业级时序数据库选型指南:技术架构与场景化实践
  • 精选五款电脑USB接口控制软件,助您高效管控USB端口
  • 有个性的个人网站js打开网站
  • tesla 2025 年在自动驾驶投入 多少钱
  • 做调查报告的网站钟点工