You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java线程池中运行多个Runnable?如何用ExecutorService并行执行多任务?

在Java线程池中运行多个Runnable实例与并行执行任务的方法

嘿,这个问题在Java并发开发里太常见了,我来一步步给你捋清楚怎么操作,保证你看完就能上手!

一、在线程池中运行多个Runnable实例

Java的ExecutorService是线程池的核心API,只要掌握它的基本用法,运行多个Runnable实例就非常简单。

步骤拆解

  1. 创建线程池实例:用Executors工具类的工厂方法快速创建(也可以自定义ThreadPoolExecutor来更精细控制参数),比如:
    • newFixedThreadPool(int nThreads):固定大小的线程池,适合任务量稳定的场景
    • newCachedThreadPool():可缓存的线程池,空闲线程会被回收,适合短期大量任务的场景
  2. 定义多个Runnable任务:可以用Lambda表达式、匿名内部类或者实现Runnable接口的类来写任务逻辑
  3. 提交任务到线程池:调用executor.submit(runnable)把任务丢进线程池,线程池会自动分配空闲线程执行
  4. 关闭线程池:任务提交完后一定要调用shutdown(),否则JVM会因为线程池的非守护线程一直运行而无法退出

代码示例

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MultiRunnablePoolDemo {
    public static void main(String[] args) {
        // 创建固定大小为3的线程池
        ExecutorService executor = Executors.newFixedThreadPool(3);

        // 定义3个不同的Runnable任务
        Runnable downloadTask = () -> {
            System.out.println("下载任务启动,线程:" + Thread.currentThread().getName());
            try {
                Thread.sleep(1500); // 模拟下载耗时
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // 重新标记中断状态
            }
            System.out.println("下载任务完成");
        };

        Runnable parseTask = () -> {
            System.out.println("解析任务启动,线程:" + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            System.out.println("解析任务完成");
        };

        Runnable saveTask = () -> {
            System.out.println("保存任务启动,线程:" + Thread.currentThread().getName());
            try {
                Thread.sleep(800);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            System.out.println("保存任务完成");
        };

        // 提交所有任务
        executor.submit(downloadTask);
        executor.submit(parseTask);
        executor.submit(saveTask);

        // 关闭线程池:停止接受新任务,等待已提交任务执行完毕
        executor.shutdown();
    }
}

二、并行执行多个不同的方法或Runnable任务

核心思路其实和上面一致——把不同的方法或逻辑包装成可被线程池执行的任务(Runnable或Callable),然后提交即可。

1. 包装普通方法为Runnable(无返回值场景)

如果你的方法不需要返回结果,直接用方法引用或者Lambda把它包装成Runnable就行:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class DifferentMethodsDemo {
    // 自定义方法A
    public static void generateReport() {
        System.out.println("生成报表中,线程:" + Thread.currentThread().getName());
        try {
            Thread.sleep(1200);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    // 自定义方法B
    public static void syncData() {
        System.out.println("同步数据中,线程:" + Thread.currentThread().getName());
        try {
            Thread.sleep(1800);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();

        // 用方法引用提交方法A
        executor.submit(DifferentMethodsDemo::generateReport);
        // 提交方法B
        executor.submit(DifferentMethodsDemo::syncData);
        // 直接提交匿名Runnable(适合临时逻辑)
        executor.submit(() -> {
            System.out.println("清理临时文件,线程:" + Thread.currentThread().getName());
            try {
                Thread.sleep(900);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        executor.shutdown();
    }
}

2. 用Callable获取方法返回值(有返回值场景)

如果需要获取方法的执行结果,就用Callable接口代替Runnable,提交后会得到一个Future对象,通过它可以拿到返回值:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableWithResultDemo {
    // 有返回值的计算方法
    public static Integer calculateAverage(int[] nums) {
        System.out.println("计算平均值中,线程:" + Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return -1;
        }
        int sum = 0;
        for (int num : nums) sum += num;
        return sum / nums.length;
    }

    // 有返回值的字符串处理方法
    public static String formatString(String input) {
        System.out.println("格式化字符串中,线程:" + Thread.currentThread().getName());
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return "处理中断";
        }
        return String.format("格式化后:%s", input.trim().toUpperCase());
    }

    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newFixedThreadPool(2);

        // 创建Callable任务
        Callable<Integer> avgTask = () -> calculateAverage(new int[]{10, 20, 30, 40});
        Callable<String> formatTask = () -> formatString("  hello java concurrency  ");

        // 提交任务并获取Future
        Future<Integer> avgFuture = executor.submit(avgTask);
        Future<String> formatFuture = executor.submit(formatTask);

        // 获取结果(会阻塞直到任务完成)
        System.out.println("平均值计算结果:" + avgFuture.get());
        System.out.println("字符串格式化结果:" + formatFuture.get());

        executor.shutdown();
    }
}

3. 批量提交并等待所有任务完成

如果有一组任务需要全部执行完再继续后续逻辑,可以用invokeAll()方法,它会阻塞直到所有任务执行完毕:

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class BatchTaskDemo {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newFixedThreadPool(3);

        // 批量创建Callable任务
        List<Callable<String>> taskList = Arrays.asList(
            () -> { Thread.sleep(800); return "用户数据同步完成"; },
            () -> { Thread.sleep(1200); return "订单数据同步完成"; },
            () -> { Thread.sleep(1000); return "商品数据同步完成"; }
        );

        // 提交所有任务并等待完成
        List<Future<String>> futures = executor.invokeAll(taskList);

        // 遍历输出所有结果
        for (Future<String> future : futures) {
            System.out.println(future.get());
        }

        executor.shutdown();
    }
}

实用小提示

  • 生产环境尽量避免用Executors的默认工厂方法(比如newCachedThreadPool可能创建大量线程导致OOM),推荐直接用ThreadPoolExecutor构造函数,自定义核心线程数、最大线程数、任务队列大小等参数,更贴合业务场景。
  • 处理InterruptedException时,记得调用Thread.currentThread().interrupt()重新标记中断状态,让上层代码能感知到中断事件。
  • 如果任务可能抛出异常,调用Future.get()时要捕获ExecutionException,并处理任务内部的异常。

内容的提问来源于stack exchange,提问作者Vignesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:38:05