
1. Java多线程的核心价值与应用场景现代Java应用开发中多线程技术早已从加分项变成了必备技能。我处理过大量高并发场景下的性能问题90%的案例都与线程使用不当有关。多线程的本质是通过时间片轮转和CPU核心的并行计算能力让单个进程能够同时处理多个任务。典型应用场景包括Web服务器处理并发请求如Tomcat的线程池后台批量数据处理如报表生成异步任务执行如消息队列消费提高GUI程序响应速度Swing的事件分发线程关键认知多线程并不总是提高性能不当使用反而会导致吞吐量下降。我曾见过一个错误使用线程池的案例创建了500个线程反而使QPS从1200降到300。2. Java内存模型与并发原理2.1 JMM的核心三要素Java内存模型(JMM)规定了线程如何与内存交互其三大核心特性需要深入理解原子性基本类型读写是原子的但i这类复合操作不是。通过AtomicInteger等工具类解决AtomicInteger counter new AtomicInteger(0); counter.incrementAndGet(); // 线程安全的自增可见性volatile关键字保证变量修改对所有线程立即可见。但要注意volatile boolean flag false; // 仅适合状态标志位不保证复合操作的原子性有序性编译器/处理器会指令重排序。通过happens-before原则约束程序顺序规则锁规则解锁先于加锁volatile变量规则线程启动/终止规则2.2 锁的底层实现原理对象头中的Mark Word存储了锁状态信息锁升级过程为 无锁 → 偏向锁 → 轻量级锁 → 重量级锁通过JOL工具可以查看对象头信息// 添加JOL依赖 Object obj new Object(); System.out.println(ClassLayout.parseInstance(obj).toPrintable());3. 线程生命周期与管控策略3.1 线程状态转换实战Java线程的6种状态NEW刚创建未start()RUNNABLE可运行包含就绪和运行中BLOCKED等待监视器锁WAITING无限期等待Object.wait()TIMED_WAITING限期等待Thread.sleep()TERMINATED执行结束通过jstack观察线程状态jstack pid | grep -A 10 java.lang.Thread.State3.2 线程中断的正确姿势常见误区直接调用stop()。正确做法Thread t new Thread(() - { while(!Thread.currentThread().isInterrupted()) { // 业务逻辑 } }); t.start(); // 优雅中断 t.interrupt();中断异常处理原则捕获InterruptedException后必须重置中断状态清理资源后再退出线程4. 线程池深度配置与调优4.1 参数配置黄金法则ThreadPoolExecutor的7个核心参数corePoolSize常驻线程数建议CPU核心数1maximumPoolSize最大线程数建议2N1N为CPU核心数keepAliveTime空闲线程存活时间unit时间单位workQueue任务队列ArrayBlockingQueue有界LinkedBlockingQueue无界threadFactory线程工厂建议自定义命名handler拒绝策略默认AbortPolicy抛出异常最佳实践配置示例ThreadPoolExecutor executor new ThreadPoolExecutor( 4, // core 8, // max 30, TimeUnit.SECONDS, new ArrayBlockingQueue(100), new NamedThreadFactory(Order-Process), new ThreadPoolExecutor.CallerRunsPolicy() );4.2 监控关键指标通过ThreadPoolExecutor提供的方法获取运行时数据getActiveCount()活动线程数getCompletedTaskCount()已完成任务数getQueue().size()队列积压量预警阈值建议活动线程数持续 最大线程数80% → 考虑扩容队列使用率 70%持续5分钟 → 告警5. 并发工具类实战技巧5.1 CountDownLatch vs CyclicBarrier对比两种同步工具特性CountDownLatchCyclicBarrier重置不可重置可重复使用计数递减计数递增计数阻塞主线程等待所有线程相互等待典型应用场景CountDownLatch启动服务时等待所有组件初始化完成CyclicBarrier多阶段并行计算如MapReduce5.2 CompletableFuture异步编排链式调用示例CompletableFuture.supplyAsync(() - queryFromDB()) .thenApplyAsync(data - transform(data)) .thenAcceptAsync(result - saveToCache(result)) .exceptionally(ex - { log.error(处理失败, ex); return null; });注意事项默认使用ForkJoinPool.commonPool()耗时IO操作建议自定义线程池避免在回调中阻塞6. 性能监控与问题排查6.1 线程堆栈分析实战使用jstack检测死锁执行jstack获取线程dump搜索deadlock关键词分析相互等待的线程链典型死锁日志特征Thread-1 #12 prio5 os_prio0 tid0x00007f48740f7000 waiting to lock 0x000000076bf62208 (a java.lang.Object) which is held by Thread-26.2 JFR深度监控启用Java Flight Recorderjava -XX:UnlockCommercialFeatures -XX:FlightRecorder ...关键监控事件jdk.ThreadPark线程阻塞事件jdk.ThreadSleep线程休眠jdk.JavaMonitorWait锁等待6.3 Arthas在线诊断常用命令示例# 查看线程CPU占用 thread -n 3 # 监控方法调用 watch com.example.Service * {params,returnObj} -x 2 # 追踪慢请求 trace com.example.Controller * #cost1007. 高频面试问题剖析7.1 线程安全三问HashMap为什么线程不安全JDK7存在环形链表问题JDK8解决死循环但仍有数据覆盖风险替代方案ConcurrentHashMap或Collections.synchronizedMapvolatile能否替代锁仅保证可见性不保证原子性适合一写多读场景复合操作仍需synchronized/CASThreadLocal内存泄漏问题强引用链Thread → ThreadLocalMap → Entry → Value解决方案使用后及时remove()7.2 并发容器选型指南场景推荐方案注意事项缓存ConcurrentHashMap注意null值限制队列LinkedBlockingQueue警惕无界队列OOM计数器LongAdder高并发统计场景延迟任务DelayQueue需实现Delayed接口8. 生产环境最佳实践8.1 线程命名规范推荐命名方式业务前缀Order-Process-Thread环境标识Prod-Payment-Thread实例编号Cache-Refresh-1通过ThreadFactory实现class NamedThreadFactory implements ThreadFactory { private final AtomicInteger counter new AtomicInteger(1); private final String prefix; public Thread newThread(Runnable r) { return new Thread(r, prefix - counter.getAndIncrement()); } }8.2 异常处理机制全局异常捕获Thread.setDefaultUncaughtExceptionHandler((t, e) - { log.error(Thread {} crashed, t.getName(), e); // 报警通知 alertService.notify(e); });线程池异常处理Future? future executor.submit(task); try { future.get(); } catch (ExecutionException e) { Throwable rootCause e.getCause(); // 处理业务异常 }8.3 上下文传递方案跨线程传递MDC信息ExecutorService executor new ThreadPoolExecutor( ..., new MdcAwareThreadFactory() ); class MdcAwareRunnable implements Runnable { private final MapString, String context; public void run() { MDC.setContextMap(context); try { delegate.run(); } finally { MDC.clear(); } } }