代码示例说明如何通过线程池实现有返回值的多线程编程

简介: 通过Callable和Future结合线程池,实现有返回值的多线程编程。Callable定义带返回值的任务,submit提交后返回Future对象,调用get()可获取结果并处理异常。支持单任务与多任务并发,适用于数据并行计算等场景,提升执行效率。

通过线程池实现有返回值的多线程编程,核心是使用 Callable 接口(定义有返回值的任务)和 Future 接口(获取任务结果)。以下是具体代码示例,包含单任务、多任务场景,并说明关键API的使用。

一、核心原理

  1. Callable<T>:泛型接口,其中 call() 方法是线程执行体,返回值类型为 T,可抛出异常。
  2. Future<T>:用于获取 Callable 任务的返回结果,通过 get() 方法阻塞等待结果(或超时获取)。
  3. 线程池:通过 ExecutorServicesubmit(Callable<T>) 方法提交任务,返回 Future<T> 对象。

二、代码示例

1. 单任务场景:提交一个有返回值的任务

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 ThreadPoolSingleCallable {
   
    public static void main(String[] args) {
   
        // 1. 创建线程池(这里用固定大小为1的线程池)
        ExecutorService executor = Executors.newFixedThreadPool(1);

        // 2. 定义有返回值的任务(实现Callable接口,泛型为返回值类型)
        Callable<Integer> task = new Callable<Integer>() {
   
            @Override
            public Integer call() throws Exception {
   
                System.out.println("任务开始执行:计算1~100的和");
                int sum = 0;
                for (int i = 1; i <= 100; i++) {
   
                    sum += i;
                }
                Thread.sleep(1000); // 模拟任务耗时
                System.out.println("任务执行完毕");
                return sum; // 返回计算结果
            }
        };

        // 3. 提交任务到线程池,获取Future对象(用于后续获取结果)
        Future<Integer> future = executor.submit(task);

        // 4. 关闭线程池(不再接受新任务,等待现有任务完成)
        executor.shutdown();

        // 5. 通过Future获取任务结果(get()会阻塞当前线程,直到任务完成)
        try {
   
            // 可选:设置超时时间,避免无限等待(如5秒超时)
            // Integer result = future.get(5, TimeUnit.SECONDS);
            Integer result = future.get();
            System.out.println("1~100的和为:" + result); // 输出:5050
        } catch (InterruptedException e) {
   
            // 线程被中断时触发
            System.out.println("任务被中断");
            e.printStackTrace();
        } catch (ExecutionException e) {
   
            // 任务执行中抛出异常时触发
            System.out.println("任务执行出错");
            e.printStackTrace();
        }
    }
}

2. 多任务场景:提交多个有返回值的任务,批量获取结果

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 ThreadPoolMultiCallable {
   
    public static void main(String[] args) {
   
        // 1. 创建线程池(核心线程数为3,适合并发执行多个任务)
        ExecutorService executor = Executors.newFixedThreadPool(3);

        // 2. 定义多个有返回值的任务(计算1~n的和,n分别为100、200、300)
        List<Callable<Integer>> tasks = new ArrayList<>();
        tasks.add(new SumTask(100));  // 任务1:1~100的和
        tasks.add(new SumTask(200));  // 任务2:1~200的和
        tasks.add(new SumTask(300));  // 任务3:1~300的和

        // 3. 批量提交任务,获取所有Future对象(存储结果的"占位符")
        List<Future<Integer>> futures = new ArrayList<>();
        for (Callable<Integer> task : tasks) {
   
            Future<Integer> future = executor.submit(task);
            futures.add(future);
        }

        // 4. 关闭线程池
        executor.shutdown();

        // 5. 遍历Future集合,获取所有任务的结果
        for (int i = 0; i < futures.size(); i++) {
   
            Future<Integer> future = futures.get(i);
            try {
   
                int result = future.get(); // 阻塞等待当前任务结果
                System.out.println("1~" + (i + 1) * 100 + "的和为:" + result);
            } catch (InterruptedException | ExecutionException e) {
   
                e.printStackTrace();
            }
        }
    }

    // 自定义Callable任务:计算1~max的和
    static class SumTask implements Callable<Integer> {
   
        private int max;

        public SumTask(int max) {
   
            this.max = max;
        }

        @Override
        public Integer call() throws Exception {
   
            int sum = 0;
            for (int i = 1; i <= max; i++) {
   
                sum += i;
            }
            System.out.println(Thread.currentThread().getName() + " 完成计算(1~" + max + ")");
            return sum;
        }
    }
}

输出结果(线程名可能不同,体现并发执行):

pool-1-thread-1 完成计算(1~100)
pool-1-thread-2 完成计算(1~200)
pool-1-thread-3 完成计算(1~300)
1~100的和为:5050
1~200的和为:20100
1~300的和为:45150

三、关键API说明

  1. executor.submit(Callable<T>)
    提交有返回值的任务,返回 Future<T> 对象。线程池会分配线程执行 call() 方法。

  2. Future<T>.get()

    • 阻塞当前线程,直到任务执行完毕并返回结果。
    • 若任务抛出异常,get() 会将异常封装为 ExecutionException 抛出。
    • 可使用 get(long timeout, TimeUnit unit) 设置超时时间,避免永久阻塞。
  3. Future<T>.isDone()
    判断任务是否执行完毕(返回 true 表示已完成,包括正常结束、异常终止、被取消)。

  4. Future<T>.cancel(boolean mayInterruptIfRunning)
    取消任务执行:

    • 若任务未开始,直接取消;
    • 若任务已开始,mayInterruptIfRunningtrue 则中断任务,否则允许任务完成。

四、优势总结

  1. 高效管理线程:线程池复用线程,减少创建/销毁开销。
  2. 批量处理任务:通过 List<Future> 批量管理多个任务的结果。
  3. 可控的结果获取Future 提供阻塞获取、超时控制等功能,灵活处理异步结果。

这种方式适合需要多线程并发计算并汇总结果的场景(如数据分片计算、并行查询等)。

相关文章
|
安全 Java 应用服务中间件
【JavaWeb】Tomcat底层机制和Servlet运行原理
网络通信:Tomcat使用Java的Socket API来监听特定的端口(通常是8080),接收来自客户端的HTTP请求。 线程池:Tomcat使用线程池来处理并发的请求。当有新的请求到达时,Tomcat会从线程池中获取一个空闲线程来处理该请求,这样可以提高处理效率。 生命周期管理:Tomcat负责管理Servlet和其他Web组件的生命周期,包括初始化、请求处理和销毁等阶段。(init(), run())
|
22天前
|
文字识别 安全 程序员
PowerToys微软官方效率工具实操教程!Windows系统增强神器!
PowerToys是微软官方推出的免费开源工具集,集成20余款高效插件,如窗口管理、快速启动、批量重命名、OCR文字提取等,显著提升Windows使用体验,支持多屏协作、快捷操作,安全稳定,持续更新,适合各类用户优化工作效率。
185 6
|
2月前
|
网络安全 数据库 索引
Everything(文件搜索工具)安装教程!电脑端最强文件搜索神器
Everything是一款毫秒级响应的轻量级文件搜索工具,直接读取NTFS文件系统MFT,无需建库索引,安装包仅1.7MB,资源占用极低。输入关键词即可瞬间定位电脑中的文件与文件夹,支持快速筛选与浏览,大幅提升文件查找效率。
352 1
|
22天前
|
区块链 数据安全/隐私保护 计算机视觉
FSViewer看图软件安装教程!可以批量格式转换、批量重命名、批量压缩的看图软件(还有其他几款看图软件可以看看)
FSViewer是一款功能强大的免费看图软件,支持BMP、JPG、PNG、GIF、RAW等主流图片格式,具备快速浏览、批量格式转换、重命名、压缩及图片编辑功能,操作简便,适合日常图像处理需求。
217 72
|
20天前
|
存储 搜索推荐 安全
电脑必备软件:PortableApps便携式软件管理工具安装使用教程:U盘装软件随身带
PortableApps是一款免费开源的便携式软件管理平台,支持将软件安装至U盘,即插即用,拔出不留痕迹。内置近500款实用软件,无需安装,跨平台使用便捷,支持个性化主题设置,让软件随身携带,工作学习更高效。
201 1
|
22天前
|
人工智能 UED Windows
Egde卸载教程!edge浏览器卸载工具!EdgeRemover v18.38新版本,单文件便携版!
Edge浏览器虽功能强大,却常因无法彻底卸载让用户体验困扰。本文推荐一款专清工具——Edge Remover,支持一键移除Edge及WebView2运行时,两种模式灵活选择,操作简单,无需专业技能,彻底清理不留残留,释放C盘空间,提升系统纯净度,是Windows用户必备的卸载利器。
395 2
|
1月前
|
Java 数据库 微服务
Java 学习路线可按「基础→进阶→实战→架构」四阶段推进
Java学习路线分四阶段:基础→进阶→实战→架构。涵盖语法、多线程、框架、微服务等核心内容,搭配项目实战与学习技巧,助你系统掌握Java开发技能,逐步成长为高级工程师。(238字)
205 4