随着多核 CPU 的普及,多线程编程已成为现代软件开发的重要技能之一。Java 自 1.0 起便内建了强大的线程支持,并在后续版本中不断增强并发能力:从基本的 Thread
、synchronized
,到 java.util.concurrent
包,再到 JDK 21 引入的虚拟线程。
本篇文章将通过图文结合与代码演示,从入门到高阶,系统梳理 Java 多线程与并发编程的核心知识。
线程是操作系统能够调度的最小执行单元。一个 Java 程序至少有一个线程(main),可以通过新建 Thread
启动多个线程并发执行。
📌 图示:进程与线程结构
css复制编辑[进程]
└─ 线程1(主线程)
└─ 线程2(工作线程)
└─ ...
java复制编辑class MyThread extends Thread {
public void run() {
System.out.println("线程执行中...");
}
}
new MyThread().start();
java复制编辑Runnable task = () -> System.out.println("使用 Runnable 执行");
new Thread(task).start();
java复制编辑Callable<Integer> task = () -> 123;
FutureTask<Integer> future = new FutureTask<>(task);
new Thread(future).start();
System.out.println(future.get());
Java 中线程的五种状态如下:
📌 图示:线程状态转移图
sql复制编辑NEW → RUNNABLE → RUNNING → WAITING/BLOCKED → TERMINATED
java复制编辑public synchronized void increment() {
count++;
}
📌 图示:synchronized 互斥机制
mathematica复制编辑Thread 1 ─┐ ┌─进入同步块
├→ 获取锁 ├→ 执行代码
Thread 2 ─┘ └─等待 Thread 1 释放锁
java复制编辑Lock lock = new ReentrantLock();
lock.lock();
try {
// 临界区
} finally {
lock.unlock();
}
可实现更细粒度的控制,如尝试加锁、可中断加锁等。
java复制编辑ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(() -> System.out.println("任务执行"));
pool.shutdown();
📌 图示:线程池原理简化图
css复制编辑 提交任务
↓
[线程池]——[任务队列]——[线程Worker]
java复制编辑Callable<Integer> task = () -> 42;
Future<Integer> result = pool.submit(task);
System.out.println(result.get()); // 阻塞直到结果返回
java复制编辑CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
new Thread(() -> {
// 模拟任务
latch.countDown();
}).start();
}
latch.await(); // 主线程等待
用途:等待多个线程完成。
java复制编辑CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("所有人就位!"));
for (int i = 0; i < 3; i++) {
new Thread(() -> {
barrier.await(); // 所有线程到达才继续执行
}).start();
}
用途:并发场景的分阶段同步。
java复制编辑Semaphore semaphore = new Semaphore(2); // 最多允许2个线程同时访问
for (int i = 0; i < 5; i++) {
new Thread(() -> {
semaphore.acquire();
System.out.println("访问资源");
semaphore.release();
}).start();
}
用途:限流/控制资源并发访问。
java复制编辑AtomicInteger counter = new AtomicInteger();
counter.incrementAndGet(); // ++
counter.getAndAdd(5); // += 5
📌 无需加锁,适合高频操作。
java复制编辑volatile boolean running = true;
public void stop() {
running = false; // 线程间可见
}
📌 用于状态标志很合适。
JDK 21 引入虚拟线程,可实现百万级并发:
java复制编辑Thread.startVirtualThread(() -> {
System.out.println("虚拟线程执行!");
});
📌 优势:
📌 图示:平台线程 vs 虚拟线程
mathematica复制编辑平台线程:1 OS 线程 ↔ 1 Java 线程
虚拟线程:N Java 线程 ↔ M OS 线程(通过调度器映射)
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 等辅助工具同步流程。
两个线程相互等待对方释放资源,导致永久阻塞。
示例:
java复制编辑synchronized (lock1) {
synchronized (lock2) {
...
}
}
同时另一个线程相反顺序获取锁,会死锁。
🔧 解决策略:
方向 | 优化建议 |
---|---|
线程池 | 根据任务类型设置合理核心数和队列容量 |
锁优化 | 使用读写锁、锁分段、原子类 |
状态控制 | 使用 volatile 配合 CAS |
内存分配 | 减少线程频繁创建/销毁 |
Java 并发编程是构建高性能、高可用系统的核心能力。本文从基础到进阶,涵盖了:
通过示例与图示辅助讲解,相信你对 Java 并发编程有了清晰的认识。随着 JDK 的演进(特别是虚拟线程的引入),Java 的并发模型正在变得更现代、更易用。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。