Java 多线程编程详解:从基础到并发实战

Java 多线程编程详解:从基础到并发实战

一、引言在现代软件开发中,多线程编程是提升应用性能、实现并发处理和响应式编程的重要技术。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 callable = () -> "任务结果";

ExecutorService pool = Executors.newSingleThreadExecutor();

Future future = pool.submit(callable);

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 queue = new ArrayBlockingQueue<>(10);生产者线程:

代码语言: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 results = new ConcurrentHashMap<>();

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 urls = Arrays.asList(

"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

相关推荐

如何投诉ofo共享单车
365体育app官方版下载

如何投诉ofo共享单车

📅 09-17 👁️ 3158
黄山硬天都多少钱一包 黄山硬天都香烟价格表图一览
365用什么浏览器登录

黄山硬天都多少钱一包 黄山硬天都香烟价格表图一览

📅 07-05 👁️ 5799
qq飞车手游结婚需要什么条件 qq飞车手游结婚步骤流程
365体育app官方版下载

qq飞车手游结婚需要什么条件 qq飞车手游结婚步骤流程

📅 07-13 👁️ 3532