首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java 多线程与并发编程实战指南

Java 多线程与并发编程实战指南

原创
作者头像
用户11690571
发布2025-06-06 11:59:55
发布2025-06-06 11:59:55
30200
代码可运行
举报
运行总次数:0
代码可运行

一、引言

随着多核 CPU 的普及,多线程编程已成为现代软件开发的重要技能之一。Java 自 1.0 起便内建了强大的线程支持,并在后续版本中不断增强并发能力:从基本的 Threadsynchronized,到 java.util.concurrent 包,再到 JDK 21 引入的虚拟线程。

本篇文章将通过图文结合与代码演示,从入门到高阶,系统梳理 Java 多线程与并发编程的核心知识。


二、Java 多线程基础

2.1 什么是线程

线程是操作系统能够调度的最小执行单元。一个 Java 程序至少有一个线程(main),可以通过新建 Thread 启动多个线程并发执行。

📌 图示:进程与线程结构

代码语言:javascript
代码运行次数:0
运行
复制
css复制编辑[进程]
 └─ 线程1(主线程)
 └─ 线程2(工作线程)
 └─ ...

2.2 创建线程的三种方式

✅ 方式 1:继承 Thread 类
代码语言:javascript
代码运行次数:0
运行
复制
java复制编辑class MyThread extends Thread {
    public void run() {
        System.out.println("线程执行中...");
    }
}

new MyThread().start();
✅ 方式 2:实现 Runnable 接口
代码语言:javascript
代码运行次数:0
运行
复制
java复制编辑Runnable task = () -> System.out.println("使用 Runnable 执行");
new Thread(task).start();
✅ 方式 3:实现 Callable + Future
代码语言:javascript
代码运行次数:0
运行
复制
java复制编辑Callable<Integer> task = () -> 123;
FutureTask<Integer> future = new FutureTask<>(task);
new Thread(future).start();
System.out.println(future.get());

三、线程生命周期详解

Java 中线程的五种状态如下:

📌 图示:线程状态转移图

代码语言:javascript
代码运行次数:0
运行
复制
sql复制编辑NEW → RUNNABLE → RUNNING → WAITING/BLOCKED → TERMINATED
  • NEW:新建状态
  • RUNNABLE:可运行,等待 CPU 调度
  • BLOCKED:等待锁资源
  • WAITING:主动等待(如 join)
  • TERMINATED:线程运行结束

四、线程同步机制

4.1 synchronized 关键字

代码语言:javascript
代码运行次数:0
运行
复制
java复制编辑public synchronized void increment() {
    count++;
}
  • 修饰方法:锁的是当前实例
  • 修饰代码块:锁的是传入对象

📌 图示:synchronized 互斥机制

代码语言:javascript
代码运行次数:0
运行
复制
mathematica复制编辑Thread 1 ─┐       ┌─进入同步块
         ├→ 获取锁 ├→ 执行代码
Thread 2 ─┘       └─等待 Thread 1 释放锁

4.2 ReentrantLock 可重入锁

代码语言:javascript
代码运行次数:0
运行
复制
java复制编辑Lock lock = new ReentrantLock();
lock.lock();
try {
    // 临界区
} finally {
    lock.unlock();
}

可实现更细粒度的控制,如尝试加锁、可中断加锁等。


五、并发工具类介绍(java.util.concurrent)

5.1 线程池 Executor 框架

代码语言:javascript
代码运行次数:0
运行
复制
java复制编辑ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(() -> System.out.println("任务执行"));
pool.shutdown();
  • FixedThreadPool:固定线程数
  • CachedThreadPool:可伸缩线程池
  • ScheduledThreadPool:定时/周期任务

📌 图示:线程池原理简化图

代码语言:javascript
代码运行次数:0
运行
复制
css复制编辑     提交任务
         ↓
[线程池]——[任务队列]——[线程Worker]

5.2 Future + Callable 获取异步结果

代码语言:javascript
代码运行次数:0
运行
复制
java复制编辑Callable<Integer> task = () -> 42;
Future<Integer> result = pool.submit(task);
System.out.println(result.get()); // 阻塞直到结果返回

六、高级并发工具详解

6.1 CountDownLatch:倒计时门闩

代码语言:javascript
代码运行次数:0
运行
复制
java复制编辑CountDownLatch latch = new CountDownLatch(3);

for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        // 模拟任务
        latch.countDown();
    }).start();
}

latch.await(); // 主线程等待

用途:等待多个线程完成。


6.2 CyclicBarrier:循环栅栏

代码语言:javascript
代码运行次数:0
运行
复制
java复制编辑CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("所有人就位!"));

for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        barrier.await(); // 所有线程到达才继续执行
    }).start();
}

用途:并发场景的分阶段同步。


6.3 Semaphore:信号量

代码语言:javascript
代码运行次数:0
运行
复制
java复制编辑Semaphore semaphore = new Semaphore(2); // 最多允许2个线程同时访问

for (int i = 0; i < 5; i++) {
    new Thread(() -> {
        semaphore.acquire();
        System.out.println("访问资源");
        semaphore.release();
    }).start();
}

用途:限流/控制资源并发访问。


七、原子类与无锁编程

7.1 AtomicInteger 示例

代码语言:javascript
代码运行次数:0
运行
复制
java复制编辑AtomicInteger counter = new AtomicInteger();
counter.incrementAndGet(); // ++
counter.getAndAdd(5);      // += 5

📌 无需加锁,适合高频操作。


八、volatile 与内存可见性

代码语言:javascript
代码运行次数:0
运行
复制
java复制编辑volatile boolean running = true;

public void stop() {
    running = false; // 线程间可见
}
  • 保证可见性
  • 不保证原子性

📌 用于状态标志很合适。


九、JDK 21 虚拟线程(Virtual Thread)

JDK 21 引入虚拟线程,可实现百万级并发:

代码语言:javascript
代码运行次数:0
运行
复制
java复制编辑Thread.startVirtualThread(() -> {
    System.out.println("虚拟线程执行!");
});

📌 优势:

  • 轻量、无需繁杂线程池
  • 自动调度
  • 更适合高并发网络应用

📌 图示:平台线程 vs 虚拟线程

代码语言:javascript
代码运行次数:0
运行
复制
mathematica复制编辑平台线程:1 OS 线程 ↔ 1 Java 线程
虚拟线程:N Java 线程 ↔ M OS 线程(通过调度器映射)

十、实战项目案例:并发爬图工具(不涉及爬虫逻辑)

需求:

  • 读取 URL 列表
  • 多线程下载图片
  • 控制最大并发为 10 个线程
代码语言:javascript
代码运行次数:0
运行
复制
java复制编辑ExecutorService pool = Executors.newFixedThreadPool(10);
List<String> urls = List.of(...);

for (String url : urls) {
    pool.submit(() -> {
        byte[] imageData = downloadImage(url); // 假设方法已定义
        saveImage(imageData);
    });
}
pool.shutdown();

📌 可引入 CountDownLatch 等辅助工具同步流程。


十一、常见并发问题与调试技巧

11.1 死锁(Deadlock)

两个线程相互等待对方释放资源,导致永久阻塞。

示例:

代码语言:javascript
代码运行次数:0
运行
复制
java复制编辑synchronized (lock1) {
    synchronized (lock2) {
        ...
    }
}

同时另一个线程相反顺序获取锁,会死锁。

🔧 解决策略:

  • 保证锁获取顺序一致
  • 设置超时时间

11.2 可视化并发分析工具

  • jconsole / VisualVM
  • Java Flight Recorder (JFR)
  • Arthas 热分析工具

十二、性能调优建议

方向

优化建议

线程池

根据任务类型设置合理核心数和队列容量

锁优化

使用读写锁、锁分段、原子类

状态控制

使用 volatile 配合 CAS

内存分配

减少线程频繁创建/销毁


总结

Java 并发编程是构建高性能、高可用系统的核心能力。本文从基础到进阶,涵盖了:

  • 多线程创建与控制
  • 同步机制与线程安全
  • 并发工具类
  • 线程池实战与虚拟线程
  • 性能调优与常见问题

通过示例与图示辅助讲解,相信你对 Java 并发编程有了清晰的认识。随着 JDK 的演进(特别是虚拟线程的引入),Java 的并发模型正在变得更现代、更易用。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、引言
  • 二、Java 多线程基础
    • 2.1 什么是线程
    • 2.2 创建线程的三种方式
      • ✅ 方式 1:继承 Thread 类
      • ✅ 方式 2:实现 Runnable 接口
      • ✅ 方式 3:实现 Callable + Future
  • 三、线程生命周期详解
  • 四、线程同步机制
    • 4.1 synchronized 关键字
    • 4.2 ReentrantLock 可重入锁
  • 五、并发工具类介绍(java.util.concurrent)
    • 5.1 线程池 Executor 框架
    • 5.2 Future + Callable 获取异步结果
  • 六、高级并发工具详解
    • 6.1 CountDownLatch:倒计时门闩
    • 6.2 CyclicBarrier:循环栅栏
    • 6.3 Semaphore:信号量
  • 七、原子类与无锁编程
    • 7.1 AtomicInteger 示例
  • 八、volatile 与内存可见性
  • 九、JDK 21 虚拟线程(Virtual Thread)
  • 十、实战项目案例:并发爬图工具(不涉及爬虫逻辑)
    • 需求:
  • 十一、常见并发问题与调试技巧
    • 11.1 死锁(Deadlock)
    • 11.2 可视化并发分析工具
  • 十二、性能调优建议
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档