文章目录
🔥 问题1:HashMap与ConcurrentHashMap的线程安全差异
问题:
在多线程环境下,HashMap和ConcurrentHashMap的线程安全性有何本质区别?请结合缓存雪崩场景说明如何选择。
答案:
- 本质区别:
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));
}
}
关键点:
- 唯一令牌:避免误删其他线程的锁;
- 锁续期:防止业务未执行完锁过期;
- Lua原子解锁:保证判断与删除的原子性。
💡 问题2:JVM内存模型与OOM实战
问题:
线上服务频繁触发OutOfMemoryError: Metaspace,如何定位?列举3种优化策略。
答案:
定位步骤:
jcmd <pid> VM.flags检查Metaspace配置(-XX:MaxMetaspaceSize=256m);jstat -gcmetacapacity <pid>观察元空间使用趋势;- MAT工具分析
ClassLoader泄露(如动态生成类未卸载)。
优化策略:
- 限制动态代理类:减少
CGLib/ASM生成的类; - 配置回收阈值:
-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m; - 重启策略:通过容器化定时重启实例释放元空间。
🔧 场景题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。
✅ 总结考察点
- 并发编程:线程安全容器、锁机制、原子操作;
- JVM调优:内存模型、OOM排查、GC策略;
- 分布式设计:分布式锁、降级策略、异步补偿;
- 框架实战:线程池参数化设计、资源竞争解决方案。
提示:实际面试中可延伸追问细节(如
synchronized锁升级过程、ThreadLocal内存泄露案例),验证候选人知识深度。
594

被折叠的 条评论
为什么被折叠?



