面试复习:Java 并发与 JVM(初中高级)—— 线程池 / 锁 / AQS / JMM / 虚拟线程 / GC 选型 / 线上排查
按🌱初级/🌿中级/🌳高级三层整理的并发与 JVM 复习笔记:线程池参数与治理、synchronized 锁升级、AQS、volatile 与 JMM、ThreadLocal、CompletableFuture、虚拟线程,以及内存模型、G1/ZGC 选型、类加载、OOM 与线上排查思路。
从一个关键词,发现新的思路。
按🌱初级/🌿中级/🌳高级三层整理的并发与 JVM 复习笔记:线程池参数与治理、synchronized 锁升级、AQS、volatile 与 JMM、ThreadLocal、CompletableFuture、虚拟线程,以及内存模型、G1/ZGC 选型、类加载、OOM 与线上排查思路。
积分服务变慢,订单服务接口全部超时,CPU 却只有 5%。jstack 看到 200 个 Tomcat 线程都阻塞在 socket read 与连接池里,根因是没设超时、队列无界、没有隔离。附拒绝策略与超时、舱壁隔离的落地写法。
接口 P99 隔几分钟就冲到 3 秒,机器 CPU 却不高。开 GC 日志、jstat 看趋势,发现老年代被一个无界的静态 Map 缓存慢慢撑满,Full GC 越来越频繁。附 JDK8 与 JDK11+ 日志参数、G1 与 CMS 取舍。
运营点了一下“导出全部订单”,服务就抛出 Java heap space 并重启。靠 HeapDumpOnOutOfMemoryError 留住现场,用 MAT 的 Dominator Tree 揪出一个 List,最后改成分页 + EasyExcel 流式写出。
消息推送网关的堆使用率一直只有 40%,容器 RSS 却每天涨一截,最后被 OOMKilled,日志里还偶发 Direct buffer memory。用 NMT、Netty 泄漏检测 PARANOID 找到忘记 release 的 ByteBuf,并给堆外内存加上限。
商品详情接口每隔几十次就慢 3 秒,日志里什么都没有。用 Arthas 的 dashboard、thread、trace、watch、stack 逐层下钻到一个连不上的备用节点,再用 jad、redefine 临时止血,最后用 profiler 火焰图复核。
服务进程在、端口通、健康检查也过,但所有业务请求都卡住,CPU 只有 2%。jstack 直接报出 Found one Java-level deadlock。本文含最小可复现代码、输出逐行解读,以及锁顺序统一、tryLock 超时、缩小锁粒度三种修法。
告警说 Java 进程 CPU 800%,接口全部超时。top -Hp → printf 转十六进制 → jstack,三步定位到一条正则的灾难性回溯。附完整命令、根因分析和三种修法。
老 JDK 不识别 cgroup,容器限 2G 却按宿主机 64G 算堆,还按 32 核起线程,结果被 OOMKilled 或越跑越慢。讲清 UseContainerSupport、MaxRAMPercentage、堆外开销、cgroup v1/v2 文件,以及容器里 jstack/jmap 的正确姿势。
一份能照着操作的 JVM 笔记:运行时数据区、对象创建与回收、G1/ZGC 怎么选、常用启动参数、jstat/jmap/jstack/arthas 的用法,以及一次大报表导出把堆撑爆的真实排查过程。