一、引言在现代软件开发中,多线程编程是提升应用性能、实现并发处理和响应式编程的重要技术。Java 作为一门从语言层级支持多线程的编程语言,在 JDK 中提供了完备的并发 API,包括 Thread、Runnable、ExecutorService、synchronized、Lock、Future、Callable、并发集合、原子变量、Fork/Join 框架等。
本篇文章将从 Java 多线程的基础概念入手,逐步深入到线程生命周期、线程通信、线程池、并发工具类的使用,结合实战项目构建一个线程池调度的爬虫工具,以图文并茂、代码为主线的形式,帮助开发者系统掌握 Java 并发编程。
二、线程基础知识2.1 什么是线程线程是程序执行的最小单位。每个 Java 程序默认启动时至少包含一个主线程(main),可以通过创建新线程来并发执行任务。
2.2 进程 vs 线程项目
进程
线程
定义
独立运行的程序实体
进程内的最小执行单元
内存空间
独立
共享(堆)
通信方式
复杂(IPC)
简单(共享变量)
开销
大
小
三、Java 创建线程的方式3.1 继承 Thread 类代码语言:javascript代码运行次数:0运行复制java复制编辑class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程运行:" + Thread.currentThread().getName());
}
}
new MyThread().start();3.2 实现 Runnable 接口代码语言:javascript代码运行次数:0运行复制java复制编辑Runnable task = () -> System.out.println("Runnable 运行:" + Thread.currentThread().getName());
new Thread(task).start();3.3 实现 Callable 接口(带返回值)代码语言:javascript代码运行次数:0运行复制java复制编辑Callable
ExecutorService pool = Executors.newSingleThreadExecutor();
Future
System.out.println("结果:" + future.get());四、线程生命周期详解4.1 生命周期状态图
新建(new)
就绪(runnable)
运行(running)
阻塞/等待/休眠(blocked/waiting/timed waiting)
终止(terminated)
五、线程安全与同步机制5.1 线程不安全示例代码语言:javascript代码运行次数:0运行复制java复制编辑int count = 0;
for (int i = 0; i < 1000; i++) {
new Thread(() -> count++).start();
}结果并非 1000,因为多个线程同时写入,发生竞态条件。
5.2 使用 synchronized 修饰代码块或方法代码语言:javascript代码运行次数:0运行复制java复制编辑synchronized(this) {
count++;
}或使用:
代码语言:javascript代码运行次数:0运行复制java复制编辑public synchronized void increment() {
count++;
}5.3 使用 Lock 接口代码语言:javascript代码运行次数:0运行复制java复制编辑ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
count++;
} finally {
lock.unlock();
}六、线程间通信6.1 wait()/notify()代码语言:javascript代码运行次数:0运行复制java复制编辑synchronized(obj) {
while (!condition) {
obj.wait();
}
// 满足条件继续
}调用 notify() 唤醒等待线程:
代码语言:javascript代码运行次数:0运行复制java复制编辑synchronized(obj) {
obj.notify();
}6.2 BlockingQueue 实现生产者-消费者代码语言:javascript代码运行次数:0运行复制java复制编辑BlockingQueue
代码语言:javascript代码运行次数:0运行复制java复制编辑queue.put("任务");消费者线程:
代码语言:javascript代码运行次数:0运行复制java复制编辑String task = queue.take();七、线程池详解(Executor 框架)7.1 使用 Executors 工具类代码语言:javascript代码运行次数:0运行复制java复制编辑ExecutorService executor = Executors.newFixedThreadPool(5);
executor.execute(() -> System.out.println("线程池任务"));7.2 常用线程池类型方法
说明
newFixedThreadPool(n)
固定线程数
newCachedThreadPool()
缓存线程池
newSingleThreadExecutor()
单线程池
newScheduledThreadPool()
定时任务线程池
7.3 自定义线程池参数(推荐)代码语言:javascript代码运行次数:0运行复制java复制编辑ThreadPoolExecutor pool = new ThreadPoolExecutor(
4, 10,
60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
new ThreadPoolExecutor.AbortPolicy()
);八、并发工具类介绍(java.util.concurrent)8.1 CountDownLatch等待多个线程完成再继续:
代码语言:javascript代码运行次数:0运行复制java复制编辑CountDownLatch latch = new CountDownLatch(3);
new Thread(() -> {
// 任务
latch.countDown();
}).start();
latch.await(); // 等待全部完成8.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();
}8.3 Semaphore控制线程数量(限流):
代码语言:javascript代码运行次数:0运行复制java复制编辑Semaphore semaphore = new Semaphore(2); // 同时最多 2 个线程
semaphore.acquire();
try {
// 执行任务
} finally {
semaphore.release();
}九、实战项目:基于线程池的网页爬虫工具9.1 项目需求 从指定网页列表中并发抓取标题
控制并发数量
使用线程池管理任务
9.2 项目结构代码语言:javascript代码运行次数:0运行复制css复制编辑爬虫线程池项目/
├── Main.java
├── CrawlerTask.java
├── ResultSaver.java9.3 CrawlerTask.java代码语言:javascript代码运行次数:0运行复制java复制编辑public class CrawlerTask implements Runnable {
private final String url;
public CrawlerTask(String url) {
this.url = url;
}
@Override
public void run() {
try {
Document doc = Jsoup.connect(url).get();
String title = doc.title();
ResultSaver.save(url, title);
} catch (IOException e) {
System.err.println("抓取失败:" + url);
}
}
}9.4 ResultSaver.java代码语言:javascript代码运行次数:0运行复制java复制编辑public class ResultSaver {
private static final Map
public static void save(String url, String title) {
results.put(url, title);
System.out.println(url + " -> " + title);
}
}9.5 Main.java代码语言:javascript代码运行次数:0运行复制java复制编辑public class Main {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(5);
List
"https://www.baidu.com",
"https://www.sina.com.cn",
"https://www.csdn.net"
);
for (String url : urls) {
pool.submit(new CrawlerTask(url));
}
pool.shutdown();
}
}运行输出:
代码语言:javascript代码运行次数:0运行复制arduino复制编辑https://www.baidu.com -> 百度一下,你就知道
https://www.csdn.net -> CSDN - 专业开发者社区
https://www.sina.com.cn -> 新浪首页十、总结本文系统讲解了 Java 多线程编程的核心知识,包括线程创建、生命周期管理、同步机制、线程池、并发控制工具、以及线程间通信。同时,通过实际项目构建了一个基于线程池的网页爬虫工具,帮助读者将理论转化为实战能力。
拓展建议: 深入学习 Java 内存模型(JMM)
使用 java.util.concurrent.atomic 原子类
掌握 Fork/Join 框架
使用高级并发库如 Akka、Disruptor