引言Java 多线程与并发编程是中高级开发者必须掌握的核心技能之一。随着多核 CPU 的普及,如何高效利用多线程处理任务成为提升系统性能的关键。本文将从基本概念、常用类库,到实战案例,图文并茂地讲解 Java 并发编程的核心知识。
一、多线程与并发的基本概念1.1 什么是线程线程(Thread) 是程序执行的最小单位,是进程中的一个执行路径。一个进程可以包含多个线程,它们共享进程的内存空间。
📌 图示:进程与线程关系
代码语言:javascript复制lua复制编辑+----------------------+
| 进程(Process) |
| +----------------+ |
| | 线程1(主线程) | |
| | 线程2 | |
| | 线程3 | |
| +----------------+ |
+----------------------+1.2 并发 vs 并行 并发(Concurrency):同一时间段内交替执行多个任务(单核 CPU 实现)
并行(Parallelism):多个任务同时执行(多核 CPU 实现)
二、Java 创建线程的三种方式2.1 继承 Thread 类代码语言:javascript复制java复制编辑public class MyThread extends Thread {
public void run() {
System.out.println("线程执行:" + Thread.currentThread().getName());
}
}使用:
代码语言:javascript复制java复制编辑new MyThread().start();2.2 实现 Runnable 接口代码语言:javascript复制java复制编辑public class MyRunnable implements Runnable {
public void run() {
System.out.println("实现 Runnable:" + Thread.currentThread().getName());
}
}使用:
代码语言:javascript复制java复制编辑new Thread(new MyRunnable()).start();2.3 使用 Callable 接口 + Future可以有返回值、可抛出异常:
代码语言:javascript复制java复制编辑Callable
return 42;
};
FutureTask
new Thread(future).start();
System.out.println("结果:" + future.get());三、线程状态与生命周期图解线程状态(Java 中 Thread.State):
代码语言:javascript复制sql复制编辑+---------+ start() +----------+
| NEW |----------------->| RUNNABLE |
+---------+ /+----------+
| / |
| 被调度 / | 运行完毕
| / v
| +----------+ +---------+
+-------->| BLOCKED | | TERMINATED
+----------+ +---------+四、线程同步与锁机制4.1 为什么需要同步?当多个线程访问共享资源时,可能会发生线程安全问题,导致数据错误或逻辑紊乱。
例如:
代码语言:javascript复制java复制编辑int count = 0;
public void add() {
count++; // 非原子操作
}4.2 使用 synchronized 实现线程安全代码语言:javascript复制java复制编辑public synchronized void add() {
count++;
}等价于:
代码语言:javascript复制java复制编辑public void add() {
synchronized(this) {
count++;
}
}📌 加锁范围建议控制精确,避免性能瓶颈。
五、常用并发工具类(JUC)Java 提供 java.util.concurrent 工具包,简称 JUC,非常强大。
5.1 CountDownLatch多个线程执行完再继续下一步:
代码语言:javascript复制java复制编辑CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
new Thread(() -> {
System.out.println("线程完成:" + Thread.currentThread().getName());
latch.countDown();
}).start();
}
latch.await(); // 主线程等待
System.out.println("全部完成");5.2 CyclicBarrier多个线程到达某个点后一起执行:
代码语言:javascript复制java复制编辑CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("所有线程准备就绪,开始执行");
});
for (int i = 0; i < 3; i++) {
new Thread(() -> {
System.out.println("线程准备好:" + Thread.currentThread().getName());
try {
barrier.await();
} catch (...) {}
}).start();
}5.3 Semaphore(信号量)控制并发数量(限流):
代码语言:javascript复制java复制编辑Semaphore semaphore = new Semaphore(2); // 最多2个线程同时执行
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
semaphore.acquire();
System.out.println("访问:" + Thread.currentThread().getName());
Thread.sleep(1000);
semaphore.release();
} catch (...) {}
}).start();
}六、线程池机制详解6.1 为什么使用线程池? 重用线程,避免频繁创建销毁
管理线程生命周期
控制最大线程数,提高系统稳定性
6.2 使用 Executors 创建线程池代码语言:javascript复制java复制编辑ExecutorService pool = Executors.newFixedThreadPool(3);
pool.execute(() -> System.out.println("任务执行"));📌 图示:线程池组成结构
代码语言:javascript复制rust复制编辑任务提交 -> 阻塞队列 -> 工作线程池 -> 执行任务
↘ 拒绝策略处理6.3 自定义线程池参数代码语言:javascript复制java复制编辑ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 5, 60, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(10),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);七、实战案例:并发爬虫框架简化版场景:使用多线程爬取多个网页数据7.1 任务类定义代码语言:javascript复制java复制编辑class CrawlerTask implements Runnable {
private String url;
public CrawlerTask(String url) {
this.url = url;
}
public void run() {
System.out.println("开始爬取:" + url);
// 模拟耗时任务
try { Thread.sleep(2000); } catch (Exception e) {}
System.out.println("完成:" + url);
}
}7.2 使用线程池爬取多个页面代码语言:javascript复制java复制编辑ExecutorService executor = Executors.newFixedThreadPool(5);
List
for (String url : urls) {
executor.submit(new CrawlerTask(url));
}
executor.shutdown();八、多线程开发的常见问题及排查技巧8.1 死锁线程 A 等待 B 的资源,B 又等待 A:
代码语言:javascript复制java复制编辑// 避免死锁的建议:按固定顺序加锁,避免嵌套锁8.2 线程泄漏线程未释放、未关闭线程池导致内存占用过高。
✅ 建议使用 shutdown() 正确关闭线程池。
九、新特性推荐:虚拟线程(Project Loom)Java 21 引入虚拟线程(Virtual Thread):
代码语言:javascript复制java复制编辑Thread.startVirtualThread(() -> {
System.out.println("虚拟线程执行");
}); 启动代价小(百万级线程)
用法接近传统线程
不再强依赖线程池
🌟 是未来并发编程方向,值得关注!
总结Java 多线程与并发编程涉及底层原理、工具类、线程池管理以及实战技巧,是深入 Java 后端开发的核心。通过掌握:
多线程创建与状态管理
锁机制与并发控制类
线程池的合理使用
实际应用案例实现
你将具备开发高并发、高性能系统的能力。