一文搞懂 Java 并发编程【附示例代码】

发布时间:2026/7/11 2:51:47

一文搞懂 Java 并发编程【附示例代码】 我是十几年Java资深开发,专注架构/面试,关注我,持续输出硬核干货。一、并发编程基础1. 线程和进程的区别?线程(Thread)和进程(Process)的区别是操作系统和并发编程的基础概念,主要区别如下:定义与本质进程 : 操作系统资源分配的基本单位 。一个进程是程序的一次执行过程,拥有独立的内存空间(堆、栈、数据段、代码段)和系统资源(如文件句柄、网络连接)。线程 : CPU调度的基本单位 ,是进程内的一个执行单元。同一进程的多个线程共享进程的资源 (内存、文件等),但拥有独立的栈和程序计数器。资源开销进程 : 创建、切换、销毁开销大,因为需要分配独立的内存空间和资源。线程 : 开销小,因为共享进程资源,创建和切换只需保存少量寄存器状态。内存与隔离性进程 : 内存相互隔离,一个进程崩溃不会直接影响 其他进程(稳定性高,但通信复杂)。线程 : 共享内存,一个线程崩溃可能导致整个进程崩溃 (稳定性低,但通信高效)。通信方式进程 : 需要进程间通信(IPC)机制,如管道、消息队列、共享内存、Socket等。线程 : 可直接读写共享变量(需同步机制,如锁、volatile)。并发性进程 : 宏观上并行(多进程同时运行),但上下文切换成本高。线程 : 轻量级并发,适合高并发任务(如Web服务器处理请求)。类比理解进程 = 工厂 拥有独立的土地(内存)、原料(资源)、工人(线程)。线程 = 工厂中的工人 共享工厂资源,协作完成生产任务。Java中的体现进程 :每个Java程序运行在一个JVM进程中。线程 :Java通过Thread类或Runnable接口创建线程,共享进程的堆内存。面试回答示例“进程是资源分配的最小单位,线程是CPU调度的最小单位。进程拥有独立的内存空间,切换开销大;线程共享进程资源,切换开销小,但需要处理同步问题。在Java中,多线程共享堆内存,适合高并发任务,而多进程更适合需要强隔离的场景。”2. 并发和并行的区别?这是一个非常核心的并发编程概念,并发 和并行 的区别可以用一个生动的比喻来概括:核心区别:并发 :是处理多个任务的能力 (逻辑上同时发生)。它关乎结构 和问题分解 。并行 :是同时执行多个任务 (物理上同时发生)。它关乎执行 和资源利用 。并发定义 :系统在一段时间内 交替处理多个任务,给人“同时”进行的错觉。在单核CPU时代,这就是实现多任务的唯一方式。关键 :任务间的快速切换 。系统通过时间片轮转,让每个任务都获得一点执行时间,从宏观上看,所有任务都在推进。目标 :提高系统的响应能力 和资源利用率 (例如,当任务A等待I/O时,切换到任务B执行,不让CPU空闲)。场景 :单核CPU上运行多个程序。一个Web服务器同时处理成千上万个用户请求(通过I/O多路复用或线程池快速切换)。你在电脑上一边听音乐,一边写文档,一边下载文件。并行定义 :系统在同一个时刻 真正同时执行多个任务。前提 :必须有多核/多CPU或多台机器等多个计算资源 。关键 :任务被分解并分配到不同资源上同时执行 。目标 :缩短任务的整体完成时间 ,提高吞吐量。场景 :在多核CPU上,一个视频编码软件同时使用多个核心来渲染不同帧。使用分布式计算集群进行大数据分析(如Hadoop/Spark)。矩阵乘法中,不同部分的计算被分配到不同核心。关系与联系并行是并发的真子集 :并行一定是并发 (因为同时执行多个任务也意味着能处理多个任务),但并发不一定是并行 (单核上的并发就不是并行)。并发是并行的基础 :一个设计良好的并发程序(任务可分解、无强依赖)更容易在并行硬件上获得性能提升 。如果程序本身不是并发设计的(一个巨大的串行任务),再多的CPU核心也无法并行执行它。现代系统通常是两者的结合 :你的多核电脑上,既有多个进程在并行执行(每个进程可能跑在不同核心上),同时每个进程内部又可能通过多线程实现并发。在编程中的体现实现并发 :多线程编程、异步I/O(async/await)、事件驱动模型。关键在于管理任务的状态和切换 ,处理竞态条件、死锁等问题。实现并行 :多进程编程(利用多核)、GPU计算、分布式计算。关键在于将问题分解为可独立执行的子任务 ,并处理任务分配、通信和结果合并 。3. 创建线程有哪些方式?在Java中,创建线程主要有以下几种方式:1.继承 Thread 类这是最基本的方式,通过继承 Thread 类并重写 ​​run()​​ 方法。public class MyThread extends Thread { @Override public void run() { System.out.println("线程执行: " + Thread.currentThread().getName()); } } // 使用 public class Main { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); // 启动线程 } }特点:简单直观Java不支持多继承,所以这种方式限制了类的继承能力线程和任务耦合在一起2.实现 Runnable 接口(推荐)更常用的方式,实现 Runnable 接口,将任务逻辑与线程分离。public class MyRunnable implements Runnable { @Override public void run() { System.out.println("线程执行: " + Thread.currentThread().getName()); } } // 使用 public class Main { public static void main(String[] args) { // 方式1:创建Thread对象时传入Runnable Thread thread = new Thread(new MyRunnable()); thread.start(); // 方式2:使用匿名内部类 Thread thread2 = new Thread(new Runnable() { @Override public void run() { System.out.println("匿名内部类方式"); } }); thread2.start(); // 方式3:使用Lambda表达式(Java 8+) Thread thread3 = new Thread(() - { System.out.println("Lambda表达式方式"); }); thread3.start(); } }优点:任务与线程解耦可以继承其他类更适合资源共享(多个线程可以共享同一个Runnable实例)3.实现 Callable 接口Callable 与 Runnable 类似,但有返回值,并且可以抛出异常。import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; public class MyCallable implements CallableString { @Override public String call() throws Exception { Thread.sleep(1000); return "任务执行完成"; } } // 使用 public class Main { public static void main(String[] args) throws Exception { // 创建Callable实例 MyCallable callable = new MyCallable(); // 包装成FutureTask FutureTaskString futureTask = new FutureTask(callable); // 创建线程并启动 Thread thread = new Thread(futureTask); thread.start(); // 获取结果(会阻塞直到任务完成) String result = futureTask.get(); System.out.println("结果: " + result); } }特点:有返回值可以抛出异常通常与ExecutorService配合使用4.使用线程池(实际开发中最常用)通过 Executor 框架创建线程池,这是企业级应用中最推荐的方式。import java.util.concurrent.*; public class Main { public static void main(String[] args) { // 1. 创建线程池 ExecutorService executor = Executors.newFixedThreadPool(5); // 2. 提交任务 // 使用Runnable executor.execute(() - { System.out.println("Runnable任务执行"); }); // 使用Callable FutureString future = executor.submit(() - { Thread.sleep(1000); return "Callable任务结果"; }); // 3. 关闭线程池 executor.shutdown(); try { // 获取Callable的结果 String result = future.get(); System.out.println(result); } catch (Exception e) { e.printStackTrace(); } } }5.使用 CompletableFuture(Java 8+)Java 8 引入的异步编程方式,功能更强大。import java.util.concurrent.CompletableFuture; public class Main { public static void main(String[] args) { // 异步执行任务 CompletableFutureString future = CompletableFuture.supplyAsync(() - { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return "异步任务结果"; }); // 异步处理结果 future.thenAccept(result - { System.out.println("接收到结果: " + result); }); // 等待任务完成 future.join(); } }6.使用 Timer/TimerTask用于定时任务,但功能有限,不推荐用于复杂场景。import java.util.Timer; import java.util.TimerTask; public class Main { public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("定时任务执行"); } }, 1000, 2000); // 延迟1秒,每2秒执行一次 } }总结对比方式优点缺点适用场景继承Thread简单直观不能继承其他类,任务与线程耦合简单的测试或演示实现Runnable解耦任务与线程,可继承其他类无返回值,不能抛出受检异常大多数业务场景实现Callable有返回值,可抛出异常使用稍复杂需要获取执行结果的场景线程池资源复用,性能好,管理方便配置相对复杂生产环境,高并发场景CompletableFuture异步编程,链式调用,功能强大学习成本较高复杂的异步编程场景Timer简单定时单线程,任务阻塞会影响其他任务简单的定时任务最佳实践建议优先使用线程池 :避免频繁创建和销毁线程推荐实现Runnable或Callable :而不是继承ThreadJava 8+推荐使用CompletableFuture :进行异步编程避免直接new Thread() :在生产环境中// 生产环境推荐写法 ExecutorService executor = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() * 2 ); // 提交任务 executor.submit(() - { // 业务逻辑 }); // 或者使用CompletableFuture CompletableFuture.runAsync(() - { // 业务逻辑 }, executor);4. 并发编程的三大核心问题?Java并发编程主要面临以下三大核心问题,它们是所有并发问题的基础:1.可见性问题(Visibility Problem)定义:一个线程对共享变量的修改,另一个线程不能立即看到。原因:现代计算机为了提升性能,采用了多级缓存架构:CPU有自己的缓存(L1、L2、L3)线程操作的是CPU缓存中的副本,而不是直接操作主内存缓存刷新到主内存的时间不确定示例代码:public class VisibilityProblem { private static boolean flag = true; public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() - { System.out.println("线程1开始执行"); while (flag) { // 空循环,等待flag变为false } System.out.println("线程1结束"); }); Thread t2 = new Thread(() - { try { Thread.sleep(1000); // 等待1秒 } catch (InterruptedException e) { e.printStackTrace(); } flag = false; // 修改共享变量 System.out.println("线程2将flag改为false"); }); t1.start(); t2.start(); t1.join(); t2.join(); } }可能的结果:线程2修改了flag为false但线程1可能永远看不到这个变化,导致无限循环这是因为线程1的CPU缓存中保存的是flag的旧值(true)解决方案:使用volatile关键字private static volatile boolean flag = true;使用synchronized同步块private static boolean flag = true; private static final Object lock = new Object(); // 线程1 synchronized(lock) { while (flag) { ... } } // 线程2 synchronized(lock) { flag = false; }使用Atomic类private static AtomicBoolean flag = new AtomicBoolean(true);2.原子性问题(Atomicity Problem)定义:一个或多个操作,要么全部执行成功,要么全部不执行,不会出现执行到一半的情况。原因:Java中的基本操作(如i++)在底层是多个步骤线程切换可能发生在这些步骤之间示例代码:public class AtomicityProblem { private static int count = 0; public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() - { for (int i = 0; i 10000; i++) { count++; // 这不是原子操作! } }); Thread t2 = new Thread(() - { for (int i = 0; i 10000; i++) { count++; // 这不是原子操作! } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("最终结果: " + count); // 可能小于20000 } }count++ 的实际步骤:读取count的值到寄存器将寄存器中的值加1将结果写回count可能的问题:线程1:读取count=0 线程2:读取count=0 线程1:计算0+1=1,写入count=1 线程2:计算0+1=1,写入count=1 结果:count=1(应该是2)解决方案:使用synchronizedprivate static int count = 0; private static final Object lock = new Object(); public static void increment() { synchronized(lock) { count++; } }使用ReentrantLockprivate static int count = 0; private static final ReentrantLock lock = new ReentrantLock(); public static void increment() { lock.lock(); try { count++; } finally { lock.unlock(); } }使用Atomic类private static AtomicInteger count = new AtomicInteger(0); public static void increment() { count.incrementAndGet(); }3.有序性问题(Ordering Problem)定义:程序执行的顺序与代码编写的顺序不一致。原因:编译器优化 :编译器可能重排指令CPU指令重排 :CPU为了性能可能重排指令内存系统重排 :内存系统可能重排读写操作示例代码(双重检查锁定的单例模式):public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { // 第一次检查 synchronized (Singleton.class) { if (instance == null) { // 第二次检查 instance = new Singleton(); // 问题在这里! } } } return instance; } }问题分析:​​instance = new Singleton();​​ 实际包含三个步骤:分配内存空间初始化对象将引用指向内存地址由于指令重排,可能变成:分配内存空间将引用指向内存地址(此时instance不为null,但对象未初始化)初始化对象导致的问题:线程A执行到步骤2时,线程B看到instance不为null,直接返回未完全初始化的对象。解决方案:使用volatile防止指令重排private static volatile Singleton instance;使用静态内部类public class Singleton { private Singleton() {} private static class Holder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return Holder.INSTANCE; } }综合示例:三大问题同时存在public class ConcurrencyProblems { // 可见性问题:没有volatile private static boolean ready = false; // 原子性问题:没有同步 private static int number = 0; public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() - { while (!ready) { // 可能永远看不到ready的变化(可见性问题) } System.out.println("number = " + number); }); Thread t2 = new Thread(() - { number = 42; // 可能被重排到ready=true之后(有序性问题) ready = true; // 可能被重排到number=42之前(有序性问题) }); t1.start(); t2.start(); Thread.sleep(1000); // 原子性问题演示 Counter counter = new Counter(); Thread t3 = new Thread(() - { for (int i = 0; i 10000; i++) { counter.increment(); // 非原子操作 } }); Thread t4 = new Thread(() - { for (int i = 0; i 10000; i++) { counter.increment(); // 非原子操作 } }); t3.start(); t4.start(); t3.join(); t4.join(); System.out.println("Counter value: " + counter.getValue()); // 可能小于20000 } static class Counter { private int value = 0; public void increment() { value++; // 非原子操作 } public int getValue() { return value; } } }解决方案总结问题类型解决方案示例可见性volatile、synchronized、Atomic类volatile boolean flag原子性synchronized、Lock、Atomic类AtomicInteger count有序性volatilevolatile Singleton instance理解这三大问题是掌握Java并发编程的基础,只有理解了这些问题,才能正确选择和使用并发工具。5. 线程的状态?NEW:新建RUNNABLE:可运行(就绪+运行)BLOCKED:阻塞(等待监视器锁)WAITING:等待(无时间限制)TIMED_WAITING:超时等待TERMINATED:终止1.线程状态总览/** * Java线程的6种状态(java.lang.Thread.State): * * 1. NEW(新建) - 线程被创建但未启动 * 2. RUNNABLE(可运行) - 线程正在JVM中执行 * 3. BLOCKED(阻塞) - 线程等待监视器锁 * 4. WAITING(等待) - 线程无限期等待其他线程通知 * 5. TIMED_WAITING(限时等待)- 线程在指定时间内等待 * 6. TERMINATED(终止) - 线程已执行完毕 * * 状态转换图: * * ┌──────┐ * │ NEW │ * └──┬───┘ * │ start() * ▼ * ┌─────────┐ * │RUNNABLE │◄──┐ * └──┬──────┘ │ * │ │ * 获得CPU│ │时间片用完/yield() * ▼ │ * ┌──────┐ │ * │运行中 │─────┘ * └──┬───┘ * │ * ▼ * ┌─────────────┐ * │TERMINATED │ * └─────────────┘ * * 阻塞/等待状态: * * RUNNABLE ──wait()/join()──► WAITING ──notify()/notifyAll()──► RUNNABLE * RUNNABLE ──sleep()/join(time)──► TIMED_WAITING ──超时/中断──► RUNNABLE * RUNNABLE ──竞争synchronized锁──► BLOCKED ──获得锁──► RUNNABLE */图片来源《剑指Java》2.详细状态解析与代码示例2.1 NEW(新建状态)public class NewStateExample { public static void main(String[] args) { // 创建线程但未调用start()方法 Thread thread = new Thread(() - { System.out.println("线程执行中..."); }); System.out.println("线程状态: " + thread.getState()); // NEW System.out.println("是否存活: " + thread.isAlive()); // false // 此时线程对象已创建,但未分配系统资源 // 不能执行,只能启动或销毁 } }2.2 RUNNABLE(可运行状态)public class RunnableStateExample { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() - { // 线程执行逻辑 for (int i = 0; i 5; i++) { System.out.println("执行次数: " + i); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.start(); // 进入RUNNABLE状态 Thread.sleep(50); System.out.println("线程状态: " + thread.getState()); // RUNNABLE System.out.println("是否存活: " + thread.isAlive()); // true // RUNNABLE状态包含两个子状态: // 1. Ready(就绪):等待CPU时间片 // 2. Running(运行):正在执行 } }2.3 BLOCKED(阻塞状态)public class BlockedStateExample { private static final Object lock = new Object(); public static void main(String[] args) throws InterruptedException { Thread thread1 = new Thread(() - { synchronized (lock) { System.out.println("线程1获得锁,执行10秒"); try { Thread.sleep(10000); // 持有锁10秒 } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread thread2 = new Thread(() - { System.out.println("线程2尝试获取锁..."); synchronized (lock) { System.out.println("线程2获得锁"); } }); thread1.start(); Thread.sleep(100); // 确保thread1先获得锁 thread2.start(); Thread.sleep(100); // 确保thread2开始执行 System.out.println("线程2状态: " + thread2.getState()); // BLOCKED // BLOCKED状态触发条件: // 1. 等待进入synchronized方法/代码块 // 2. 等待重新进入synchronized方法/代码块(不会发生) } }2.4 WAITING(无限期等待状态)public class WaitingStateExample { private static final Object lock = new Object(); public static void main(String[] args) throws InterruptedException { Thread waitingThread = new Thread(() - { synchronized (lock) { try { System.out.println("线程进入WAITING状态"); lock.wait(); // 释放锁并无限期等待 System.out.println("线程被唤醒"); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread notifyingThread = new Thread(() - { try { Thread.sleep(2000); // 等待2秒 synchronized (lock) { lock.notify(); // 唤醒等待的线程 System.out.println("发送通知"); } } catch (InterruptedException e) { e.printStackTrace(); } }); waitingThread.start(); Thread.sleep(100); // 确保waitingThread先执行 System.out.println("等待线程状态: " + waitingThread.getState()); // WAITING notifyingThread.start(); // 等待两个线程执行完毕 waitingThread.join(); notifyingThread.join(); // 进入WAITING状态的方法: // 1. Object.wait() - 需要先获得对象锁 // 2. Thread.join() - 等待其他线程终止 // 3. LockSupport.park() - 底层实现 } }2.5 TIMED_WAITING(限时等待状态)public class TimedWaitingStateExample { public static void main(String[] args) throws InterruptedException { // 示例1: Thread.sleep() Thread sleepThread = new Thread(() - { try { System.out.println("线程开始sleep"); Thread.sleep(5000); // 睡眠5秒 System.out.println("线程sleep结束"); } catch (InterruptedException e) { e.printStackTrace(); } }); // 示例2: Object.wait(timeout) Object lock = new Object(); Thread waitThread = new Thread(() - { synchronized (lock) { try { System.out.println("线程开始timed wait"); lock.wait(3000); // 等待3秒 System.out.println("线程wait结束"); } catch (InterruptedException e) { e.printStackTrace(); } } }); // 示例3: Thread.join(timeout) Thread workerThread = new Thread(() - { try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } }); Thread joinThread = new Thread(() - { try { System.out.println("开始join其他线程"); workerThread.join(2000); // 等待workerThread 2秒 System.out.println("join结束"); } catch (InterruptedException e) { e.printStackTrace(); } }); sleepThread.start(); Thread.sleep(100); System.out.println("sleepThread状态: " + sleepThread.getState()); // TIMED_WAITING waitThread.start(); Thread.sleep(100); System.out.println("waitThread状态: " + waitThread.getState()); // TIMED_WAITING workerThread.start(); joinThread.start(); Thread.sleep(100); System.out.println("joinThread状态: " + joinThread.getState()); // TIMED_WAITING // 进入TIMED_WAITING状态的方法: // 1. Thread.sleep(long millis) // 2. Object.wait(long timeout) // 3. Thread.join(long millis) // 4. LockSupport.parkNanos() // 5. LockSupport.parkUntil() } }2.6 TERMINATED(终止状态)public class TerminatedStateExample { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() - { System.out.println("线程开始执行"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程执行结束"); }); System.out.println("启动前状态: " + thread.getState()); // NEW thread.start(); Thread.sleep(500); System.out.println("执行中状态: " + thread.getState()); // TIMED_WAITING thread.join(); // 等待线程结束 System.out.println("结束后状态: " + thread.getState()); // TERMINATED System.out.println("是否存活: " + thread.isAlive()); // false // TERMINATED状态特点: // 1. 线程执行完run()方法 // 2. 线程抛出未捕获异常 // 3. 不能再次启动(调用start()会抛IllegalThreadStateException) // 尝试重新启动已终止的线程 try { thread.start(); // 抛出异常 } catch (IllegalThreadStateException e) { System.out.println("异常: " + e.getMessage()); } } }3.线程状态转换实战public class ThreadStateTransition { private static final Object lock = new Object(); public static void main(String[] args) throws InterruptedException { System.out.println("=== 线程状态转换演示 ==="); // 创建线程 Thread thread = new Thread(() - { System.out.println("1. 线程启动,状态: " + Thread.currentThread().getState()); synchronized (lock) { System.out.println("2. 获得锁,执行任务"); try { Thread.sleep(1000); // TIMED_WAITING System.out.println("3. sleep结束"); lock.wait(2000); // TIMED_WAITING System.out.println("5. wait结束"); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("6. 线程即将结束"); }); System.out.println("A. 创建后状态: " + thread.getState()); // NEW thread.start(); Thread.sleep(50); System.out.println("B. 启动后状态: " + thread.getState()); // RUNNABLE或TIMED_WAITING Thread.sleep(100); System.out.println("C. sleep中状态: " + thread.getState()); // TIMED_WAITING // 创建另一个线程竞争锁 Thread blocker = new Thread(() - { synchronized (lock) { System.out.println("4. 另一个线程获得锁"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread.sleep(1200); // 等待第一个线程进入wait blocker.start(); Thread.sleep(100); System.out.println("D. wait中状态: " + thread.getState()); // TIMED_WAITING Thread.sleep(2200); // wait超时,但锁被占用 System.out.println("E. wait超时但锁被占: " + thread.getState()); // BLOCKED thread.join(); blocker.join(); System.out.println("F. 最终状态: " + thread.getState()); // TERMINATED } }6. ThreadLocal原理与使用示例?ThreadLocal 核心原理图示ThreadLocal 使用示例示例1:基本使用public class ThreadLocalBasicExample { private static final ThreadLocalInteger threadLocal = new ThreadLocal(); public static void main(String[] args) { new Thread(() - { threadLocal.set(1); System.out.println("thread-1: " + threadLocal.get()); }).start(); new Thread(() - { threadLocal.set(2); System.out.println("thread-2: " + threadLocal.get()); }).start(); new Thread(() - { System.out.println("thread-3: " + threadLocal.get()); }).start(); } }示例2:Web应用中的用户上下文public class UserContextHolder { // 存储用户信息 private static final ThreadLocalUser currentUser = new ThreadLocal(); // 存储请求ID private static final ThreadLocalString requestId = new ThreadLocal(); // 存储语言环境 private static final ThreadLocalLocale locale = ThreadLocal.withInitial(() - Locale.getDefault()); public static class User { private Long id; private String username; private String role; // getters/setters } // 设置当前用户 public static void setCurrentUser(User user) { currentUser.set(user); } // 获取当前用户 public static User getCurrentUser() { return currentUser.get(); } // 设置请求ID public static void setRequestId(String id) { requestId.set(id); } // 获取请求ID public static String getRequestId() { return requestId.get(); } // 清理所有 ThreadLocal 变量 public static void clear() { currentUser.remove(); requestId.remove(); locale.remove(); } } // 在过滤器中使用 public class UserContextFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { // 从请求中获取用户信息 User user = extractUserFromRequest(request); UserContextHolder.setCurrentUser(user); // 生成请求ID String requestId = UUID.randomUUID().toString(); UserContextHolder.setRequestId(requestId); // 继续处理请求 chain.doFilter(request, response); } finally { // 必须清理,避免内存泄漏 UserContextHolder.clear(); } } private User extractUserFromRequest(ServletRequest request) { // 实际应用中从 Session 或 Token 中获取 return new User(); } }示例3:数据库连接管理public class ConnectionManager { // 每个线程持有自己的数据库连接 private static final ThreadLocalConnection connectionHolder = new ThreadLocalConnection() { @Override protected Connection initialValue() { return createConnection(); } }; // 获取线程本地的连接 public static Connection getConnection() { return connectionHolder.get(); } // 开启事务 public static void beginTransaction() { try { Connection conn = getConnection(); conn.setAutoCommit(false); } catch (SQLException e) { throw new RuntimeException("开启事务失败", e); } } // 提交事务 public static void commit() { try { Connection conn = getConnection(); conn.commit(); conn.setAutoCommit(true); } catch (SQLException e) { throw new RuntimeException("提交事务失败", e); } } // 回滚事务 public static void rollback() { try { Connection conn = getConnection(); conn.rollback(); conn.setAutoCommit(true); } catch (SQLException e) { throw new RuntimeException("回滚事务失败", e); } } // 关闭连接(在线程结束时调用) public static void closeConnection() { Connection conn = connectionHolder.get(); if (conn != null) { try { conn.close(); } catch (SQLException e) { // 记录日志 } finally { connectionHolder.remove(); } } } private static Connection createConnection() { // 创建数据库连接 return null; // 实际返回 Connection 对象 } }示例4:性能监控public class PerformanceMonitor { // 记录方法调用耗时 private static final ThreadLocalLong startTime = new ThreadLocal(); // 记录调用栈深度 private static final ThreadLocalInteger callDepth = ThreadLocal.withInitial(() - 0); // 记录 SQL 执行次数 private static final ThreadLocalInteger sqlCount = ThreadLocal.withInitial(() - 0); public static void start(String methodName) { startTime.set(System.currentTimeMillis()); callDepth.set(callDepth.get() + 1); StringBuilder indent = new StringBuilder(); for (int i = 0; i callDepth.get(); i++) { indent.append(" "); } System.out.println(indent + "▶ " + methodName); } public static void end(String methodName) { long duration = System.currentTimeMillis() - startTime.get(); StringBuilder in

相关新闻