用代码示例说明如何通过线程池实现Java多线程编程
在Java中,线程池是管理多线程的高效方式,它通过复用线程减少频繁创建/销毁线程的开销。以下通过代码示例详细说明如何使用线程池实现多线程编程,包括线程池的创建、提交任务、获取结果及关闭线程池等核心操作。
一、线程池核心API简介
Java通过java.util.concurrent包提供线程池支持,核心类和接口:
ExecutorService:线程池核心接口,定义了提交任务、关闭线程池等方法。Executors:工具类,提供快速创建常见线程池的静态方法(实际开发中推荐ThreadPoolExecutor自定义线程池,更灵活)。ThreadPoolExecutor:线程池的核心实现类,可自定义核心线程数、最大线程数等参数。
二、线程池使用步骤(代码示例)
1. 基本使用:提交Runnable任务(无返回值)
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolRunnableDemo {public static void main(String[] args) {// 1. 创建线程池(这里用Executors.newFixedThreadPool创建固定大小的线程池)// 核心线程数为3,即同时最多运行3个线程ExecutorService executor = Executors.newFixedThreadPool(3);// 2. 提交任务(Runnable接口,无返回值)for (int i = 0; i < 5; i++) { // 提交5个任务final int taskId = i; // 任务编号// 提交Runnable任务executor.submit(new Runnable() {@Overridepublic void run() {// 任务逻辑:打印线程名和任务ID,模拟耗时操作System.out.println("线程" + Thread.currentThread().getName() + " 执行任务" + taskId);try {Thread.sleep(1000); // 模拟任务耗时1秒} catch (InterruptedException e) {e.printStackTrace();}}});}// 3. 关闭线程池(重要!否则程序会一直运行)// shutdown():不再接受新任务,等待已有任务执行完毕后关闭executor.shutdown();}
}
输出说明:
线程池有3个核心线程,5个任务会分两批执行(前3个同时执行,1秒后执行剩余2个),输出类似:
线程pool-1-thread-1 执行任务0
线程pool-1-thread-2 执行任务1
线程pool-1-thread-3 执行任务2
(1秒后)
线程pool-1-thread-1 执行任务3
线程pool-1-thread-2 执行任务4
2. 提交Callable任务(有返回值)
如果需要线程返回结果,可提交Callable任务,通过Future获取结果。
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;public class ThreadPoolCallableDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {// 1. 创建线程池(单线程池,仅1个线程)ExecutorService executor = Executors.newSingleThreadExecutor();// 2. 提交Callable任务(有返回值,这里返回1~n的和)Callable<Integer> task = new Callable<Integer>() {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 1; i <= 100; i++) {sum += i;}return sum; // 返回计算结果}};// 提交任务并获取Future对象(用于获取结果)Future<Integer> future = executor.submit(task);// 3. 关闭线程池executor.shutdown();// 4. 通过Future获取结果(get()会阻塞,直到任务完成)int result = future.get();System.out.println("1~100的和:" + result); // 输出:5050}
}
多任务批量获取结果示例:
public class ThreadPoolMultiCallableDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {// 创建固定大小为2的线程池ExecutorService executor = Executors.newFixedThreadPool(2);// 存储多个Future对象List<Future<Integer>> futures = new ArrayList<>();// 提交3个任务(计算1~n的和)for (int i = 1; i <= 3; i++) {final int num = i * 100; // 分别计算1~100、1~200、1~300的和Future<Integer> future = executor.submit(new Callable<Integer>() {@Overridepublic Integer call() throws Exception {int sum = 0;for (int j = 1; j <= num; j++) {sum += j;}return sum;}});futures.add(future);}// 关闭线程池executor.shutdown();// 遍历Future获取所有结果for (int i = 0; i < futures.size(); i++) {System.out.println("1~" + (i + 1) * 100 + "的和:" + futures.get(i).get());}}
}
输出:
1~100的和:5050
1~200的和:20100
1~300的和:45150
3. 自定义线程池(ThreadPoolExecutor)
Executors创建的线程池有潜在风险(如newCachedThreadPool可能创建大量线程导致OOM),实际开发中推荐用ThreadPoolExecutor自定义参数:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class CustomThreadPoolDemo {public static void main(String[] args) {// 自定义线程池参数int corePoolSize = 2; // 核心线程数(常驻线程)int maximumPoolSize = 4; // 最大线程数(核心线程+临时线程)long keepAliveTime = 60; // 临时线程空闲时间TimeUnit unit = TimeUnit.SECONDS; // 时间单位// 任务队列(容量为2,超出的任务会创建临时线程)ArrayBlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);// 创建自定义线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue);// 提交5个任务for (int i = 0; i < 5; i++) {final int taskId = i;executor.submit(new Runnable() {@Overridepublic void run() {System.out.println("线程" + Thread.currentThread().getName() + " 执行任务" + taskId);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});}// 关闭线程池executor.shutdown();}
}
参数说明:
- 核心线程数2,任务队列容量2。提交5个任务时:
- 前2个任务由核心线程执行;
- 中间2个任务放入队列等待;
- 第5个任务触发创建临时线程(最大线程数4,因此可创建2个临时线程)。
三、线程池常用方法
| 方法 | 说明 |
|---|---|
submit(Runnable) | 提交无返回值的任务,返回Future<?> |
submit(Callable<T>) | 提交有返回值的任务,返回Future<T> |
shutdown() | 平缓关闭:不再接受新任务,等待现有任务完成后关闭 |
shutdownNow() | 强制关闭:尝试中断所有任务,返回未执行的任务 |
isShutdown() | 判断线程池是否已关闭 |
isTerminated() | 判断所有任务是否执行完毕 |
四、线程池优势总结
- 复用线程:减少线程创建/销毁的资源消耗。
- 控制并发数:避免线程过多导致的系统资源耗尽。
- 管理任务队列:有序执行任务,避免任务丢失。
- 提高响应速度:核心线程常驻,无需等待线程创建即可执行任务。
通过线程池实现多线程编程是工业级开发的最佳实践,需根据业务场景合理选择线程池类型和参数。
