Java 多线程详解:从基础到实战,彻底掌握并发编程核心技能

作为一名 Java 开发工程师,你一定在实际开发中遇到过需要同时处理多个任务的场景,比如:并发处理请求、异步日志写入、定时任务、高并发数据处理、多用户访问等。在这些场景中,Java 多线程(Multithreading) 是你必须掌握的核心技能。

Java 从诞生之初就对多线程提供了强大的支持。随着 Java 5 引入 java.util.concurrent 包、Java 8 的 CompletableFuture、Java 9 的 Flow API 等,Java 的并发模型越来越强大和易用。

本文将带你全面掌握:

  • Java 多线程的基本概念(线程、进程、并发、并行)
  • 线程的创建与启动方式(Thread、Runnable、Callable)
  • 线程生命周期与状态管理
  • 线程同步与线程安全(synchronized、volatile、Lock)
  • 线程通信(wait/notify、Condition)
  • 线程池(ExecutorService、ThreadPoolExecutor)
  • 并发工具类(CountDownLatch、CyclicBarrier、Semaphore)
  • Future 与 CompletableFuture
  • 多线程在实际项目中的应用场景
  • 多线程常见误区与最佳实践

并通过丰富的代码示例和真实项目场景讲解,帮助你写出更高效、更安全、结构更清晰的 Java 多线程代码。


一、什么是多线程?

✅ 线程(Thread) 是什么?

线程是操作系统调度的最小单位,一个进程中可以有多个线程,它们共享进程的资源。

✅ 进程(Process) 是什么?

进程是程序的一次执行过程,拥有独立的内存空间。

✅ 并发(Concurrency) vs 并行(Parallelism)

对比项 并发 并行
定义 多个任务交替执行(时间片轮转) 多个任务同时执行(多核 CPU)
适用场景 单核 CPU、任务切换频繁 多核 CPU、计算密集型任务

二、线程的创建方式

✅ 方式1:继承 Thread 类

public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("线程运行中:" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start();
    }
}

✅ 方式2:实现 Runnable 接口

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程运行中:" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable());
        t.start();
    }
}

✅ 方式3:使用 Callable 和 Future 获取返回值

public class MyCallable implements Callable {
    @Override
    public String call() {
        return "任务完成:" + Thread.currentThread().getName();
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future future = executor.submit(new MyCallable());
        System.out.println(future.get());
        executor.shutdown();
    }
}

三、线程的生命周期与状态

线程有 6种状态,通过 Thread.State 枚举表示:

状态 描述
NEW 线程已创建,尚未启动
RUNNABLE 正在运行或等待 CPU 资源
BLOCKED 等待获取锁(阻塞)
WAITING 无限期等待(如 Object.wait()
TIMED_WAITING 有时间限制的等待(如 Thread.sleep()
TERMINATED 线程已结束

四、线程同步与线程安全

✅ 1. synchronized 关键字

public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }
}

✅ 2. ReentrantLock(显式锁)

public class Counter {
    private int count = 0;
    private Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
}

✅ 3. volatile 关键字(保证可见性)

private volatile boolean running = true;

public void stop() {
    running = false;
}

五、线程通信机制

✅ 1. wait() / notify() / notifyAll()

synchronized (lock) {
    while (conditionNotMet) {
        lock.wait(); // 释放锁,等待通知
    }
    // 条件满足,继续执行
}

✅ 2. Condition(配合 ReentrantLock 使用)

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();

lock.lock();
try {
    while (conditionNotMet) {
        condition.await();
    }
    condition.signal();
} finally {
    lock.unlock();
}

六、线程池(ThreadPool)详解

线程池可以复用线程资源,减少频繁创建和销毁线程的开销

✅ Java 提供的线程池(java.util.concurrent.Executors

线程池类型 特点
newFixedThreadPool 固定大小线程池
newCachedThreadPool 缓存线程池,按需创建
newSingleThreadExecutor 单线程池,保证顺序执行
newScheduledThreadPool 支持定时任务的线程池

✅ 示例:使用线程池执行任务

ExecutorService executor = Executors.newFixedThreadPool(4);
for (int i = 0; i < 10; i++) {
    final int task = i;
    executor.execute(() -> {
        System.out.println("执行任务:" + task + ",线程:" + Thread.currentThread().getName());
    });
}
executor.shutdown();

七、并发工具类

✅ 1. CountDownLatch(倒计时门闩)

CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        // 执行任务
        latch.countDown();
    }).start();
}
latch.await(); // 等待所有线程完成

✅ 2. CyclicBarrier(循环屏障)

适用于多个线程相互等待,全部到达后再继续执行。

CyclicBarrier barrier = new CyclicBarrier(3, () -> {
    System.out.println("所有线程到达屏障");
});
for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        // 执行任务
        barrier.await();
    }).start();
}

✅ 3. Semaphore(信号量)

用于控制同时访问的线程数量。

Semaphore semaphore = new Semaphore(2); // 同时允许2个线程访问
semaphore.acquire(); // 获取许可
// 执行操作
semaphore.release(); // 释放许可

八、Future 与 CompletableFuture

✅ Future:获取异步任务的结果

Future future = executor.submit(() -> "任务完成");
String result = future.get(); // 阻塞直到任务完成

✅ CompletableFuture:链式异步编程(Java 8+)

CompletableFuture future = CompletableFuture.supplyAsync(() -> {
    // 异步任务
    return "结果";
});
future.thenApply(result -> result + "处理完成")
      .thenAccept(System.out::println);

九、多线程在实际项目中的应用场景

场景1:并发处理订单(电商系统)

List orders = getOrders();
ExecutorService executor = Executors.newFixedThreadPool(10);
orders.forEach(order -> executor.submit(() -> processOrder(order)));
executor.shutdown();

场景2:定时任务调度(如日志清理、缓存刷新)

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
    cleanLogs();
}, 0, 1, TimeUnit.DAYS);

场景3:异步发送邮件(Spring Boot)

@Async
public void sendEmail(String to, String content) {
    // 发送邮件逻辑
}

场景4:并行计算(如大数据处理)

List data = getData();
int sum = data.parallelStream().mapToInt(Integer::intValue).sum();

十、常见误区与注意事项

误区 正确做法
忽略线程安全 使用同步机制(synchronized、Lock)
不关闭线程池 使用 executor.shutdown()
不处理异常 捕获异常或使用 UncaughtExceptionHandler
不限制线程数量 使用线程池控制并发数
直接使用 Thread.sleep() 控制顺序 使用 CountDownLatch 或 CyclicBarrier
不使用线程本地变量 使用 ThreadLocal 隔离线程数据
不使用并发工具类 使用 java.util.concurrent 包中的工具
不考虑线程复用 使用线程池复用线程
忽略 CPU 密集型任务 使用 ForkJoinPool 或 parallelStream
不使用异步编程 使用 CompletableFuture 提高响应性

十一、总结:Java 多线程核心知识点一览表

内容 说明
线程创建方式 继承 Thread、实现 Runnable、Callable
线程状态 NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED
线程同步 synchronized、ReentrantLock、volatile
线程通信 wait/notify、Condition
线程池 FixedThreadPool、CachedThreadPool、ScheduledThreadPool
并发工具类 CountDownLatch、CyclicBarrier、Semaphore
异步编程 Future、CompletableFuture
实际应用 订单处理、定时任务、异步邮件、并行计算
最佳实践 使用线程池、显式同步、处理异常、避免死锁

十二、附录:Java 多线程常用技巧速查表

技巧 示例
获取当前线程名 Thread.currentThread().getName()
设置线程优先级 thread.setPriority(Thread.MAX_PRIORITY)
设置守护线程 thread.setDaemon(true)
线程休眠 Thread.sleep(1000)
中断线程 thread.interrupt()
获取线程组 Thread.currentThread().getThreadGroup()
使用 ThreadLocal private static ThreadLocal userLocal = new ThreadLocal<>();
使用 ForkJoinPool ForkJoinPool pool = new ForkJoinPool();
使用并行流 list.parallelStream().forEach(...)
设置线程名称 new Thread(runnable, "MyThread")

如果你希望系统回顾 Java 多线程编程的核心知识与实战技巧,这篇文章将为你提供完整的知识体系和实用的编程技巧。

欢迎点赞、收藏、转发,也欢迎留言交流你在实际项目中遇到的多线程相关问题。我们下期再见

关注我,获取更多Java核心技术深度解析!

你可能感兴趣的:(java合集,开发语言,学习,java,个人开发,后端)