Java 多线程与并发编程实战指南【图文详解】

Java 多线程与并发编程实战指南【图文详解】

引言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 task = () -> {

return 42;

};

FutureTask future = new FutureTask<>(task);

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 urls = List.of("http://a.com", "http://b.com", "http://c.com");

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 后端开发的核心。通过掌握:

多线程创建与状态管理

锁机制与并发控制类

线程池的合理使用

实际应用案例实现

你将具备开发高并发、高性能系统的能力。

相关推荐

为什么还有那么多人在用QQ?
bet官网365app下载

为什么还有那么多人在用QQ?

📅 10-28 👁️ 461
分享抚州野钓大板鲫钓点
365bet线

分享抚州野钓大板鲫钓点

📅 09-20 👁️ 7460
dnf哪个图黑色陨石
bet官网365app下载

dnf哪个图黑色陨石

📅 07-27 👁️ 7183