线程池 ThreadPoolExecutor ForkJoinPool

 线程池

            线程池是 Java 并发编程中非常重要的组件,它通过重用线程来减少线程创建和销毁的开销,提高系统性能和资源利用率。

一、线程池核心参数

            Java 线程池的核心参数在 ThreadPoolExecutor 中定义:

            (1) corePoolSize:核心线程数,线程池长期保持的线程数量
            (2) maximumPoolSize:最大线程数,线程池允许的最大线程数量
            (3) keepAliveTime:非核心线程空闲超时时间
            (4) unit:超时时间单位
            (5) workQueue:任务等待队列
            (6) threadFactory:线程创建工厂
            (7) handler:任务拒绝策略

二、常用线程池及区别对比

        Java 通过 Executors 提供了四种常用线程池:

        线程池类型:
                FixedThreadPool
                            固定线程数量,核心线程数 = 最大线程数
                            负载较重的服务器,为了资源管理
                            核心线程数 = 最大线程数,队列容量无限
                CachedThreadPool
                            可缓存线程,核心线程数 = 0,最大线程数很大
                            执行大量短期异步任务    
                            核心线程 = 0,最大线程数无限,同步队列
        
                  SingleThreadExecutor
                            单线程,所有任务顺序执行
                            需要保证任务顺序执行的场景    
                            核心线程 = 1,最大线程 = 1,无界队列
                  ScheduledThreadPool    
                            支持定时及周期性任务执行
                            需要定时任务或周期性任务的场景
                            核心线程固定,最大线程无限
                    ForkJoinPool
                            工作窃取算法,并行处理    
                            大型可分解任务(如计算)
                            并行级别通常为 CPU 核心数

三、使用示例代码

public class ThreadPoolExamples {

    public static void main(String[] args) {
        // 1. 固定大小线程池示例
        fixedThreadPoolExample();
        
        // 2. 缓存线程池示例
        cachedThreadPoolExample();
        
        // 3. 单线程线程池示例
        singleThreadExecutorExample();
        
        // 4. 定时任务线程池示例
        scheduledThreadPoolExample();

        // 5. ForkJoinPool 示例
        testForkJoinPool();
    }

    /**
     * 固定大小线程池示例
     * 核心线程数和最大线程数相等
     */
    private static void fixedThreadPoolExample() {
        System.out.println("=== FixedThreadPool 示例 ===");
        // 创建固定大小为3的线程池
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        
        for (int i = 0; i < 5; i++) {
            final int taskNum = i;
            fixedThreadPool.execute(() -> {
                System.out.println("FixedThreadPool任务 " + taskNum + " 由线程 " + 
                                   Thread.currentThread().getName() + " 执行");
                try {
                    // 模拟任务执行时间
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        
        // 关闭线程池
        fixedThreadPool.shutdown();
    }

    /**
     * 缓存线程池示例
     * 线程数量根据任务动态调整
     */
    private static void cachedThreadPoolExample() {
        System.out.println("\n=== CachedThreadPool 示例 ===");
        // 创建缓存线程池
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        
        for (int i = 0; i < 5; i++) {
            final int taskNum = i;
            // 延迟提交任务,观察线程复用情况
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            cachedThreadPool.execute(() -> {
                System.out.println("CachedThreadPool任务 " + taskNum + " 由线程 " + 
                                   Thread.currentThread().getName() + " 执行");
                try {
                    // 模拟任务执行时间
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        
        // 关闭线程池
        cachedThreadPool.shutdown();
    }    

    /**
     * 单线程线程池示例
     * 所有任务由一个线程按顺序执行
     */
    private static void singleThreadExecutorExample() {
        System.out.println("\n=== SingleThreadExecutor 示例 ===");
        // 创建单线程线程池
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        
        for (int i = 0; i < 5; i++) {
            final int taskNum = i;
            singleThreadExecutor.execute(() -> {
                System.out.println("SingleThreadExecutor任务 " + taskNum + " 由线程 " + 
                                   Thread.currentThread().getName() + " 执行");
                try {
                    // 模拟任务执行时间
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        
        // 关闭线程池
        singleThreadExecutor.shutdown();
    }  

    /**
     * 定时任务线程池示例
     * 支持定时执行和周期性执行任务
     */
    private static void scheduledThreadPoolExample() {
        System.out.println("\n=== ScheduledThreadPool 示例 ===");
        // 创建定时任务线程池,核心线程数为2
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);
        
        // 1. 延迟执行任务:延迟1秒后执行
        scheduledThreadPool.schedule(() -> {
            System.out.println("延迟任务执行: " + Thread.currentThread().getName());
        }, 1, TimeUnit.SECONDS);
        
        // 2. 周期性执行任务:延迟2秒后开始,每3秒执行一次
        scheduledThreadPool.scheduleAtFixedRate(() -> {
            System.out.println("周期性任务执行: " + Thread.currentThread().getName() + 
                              ",时间: " + System.currentTimeMillis());
        }, 2, 3, TimeUnit.SECONDS);
        
        // 运行一段时间后关闭
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        scheduledThreadPool.shutdown();
    }  

    // 5. ForkJoinPool 示例(并行计算)
    private static void testForkJoinPool() throws ExecutionException, InterruptedException {
        System.out.println("\n=== ForkJoinPool 示例 ===");
        // 创建ForkJoinPool,默认并行度为CPU核心数
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        
        // 计算1到10_000_000的和
        long start = System.currentTimeMillis();
        ForkJoinTask<Long> task = new SumTask(1, 10_000_000);
        Long result = forkJoinPool.submit(task).get();
        long end = System.currentTimeMillis();
        
        System.out.println("计算结果: " + result);
        System.out.println("耗时: " + (end - start) + "ms");
        forkJoinPool.shutdown();
    }

    // ForkJoin任务:计算指定范围内的整数和
    static class SumTask extends RecursiveTask<Long> {
        // 任务拆分阈值
        private static final long THRESHOLD = 10000;
        private long start;
        private long end;

        public SumTask(long start, long end) {
            this.start = start;
            this.end = end;
        }

        @Override
        protected Long compute() {
            // 如果任务足够小,直接计算
            if (end - start <= THRESHOLD) {
                long sum = 0;
                for (long i = start; i <= end; i++) {
                    sum += i;
                }
                return sum;
            } else {
                // 任务太大,拆分
                long mid = (start + end) / 2;
                SumTask leftTask = new SumTask(start, mid);
                SumTask rightTask = new SumTask(mid + 1, end);
                
                // 并行执行子任务
                leftTask.fork();
                rightTask.fork();
                
                // 合并结果
                return leftTask.join() + rightTask.join();
            }
        }
    }
}

四、线程池使用注意事项

    1.避免使用 Executors 工具类创建线程池:
                在生产环境中,建议直接使用 ThreadPoolExecutor 构造函数,以便明确线程池参数,避免资源耗尽风险。
    2.合理设置线程池参数:
                (1) CPU 密集型任务:线程数 = CPU 核心数 + 1
                (2) IO 密集型任务:线程数 = CPU 核心数 * 2
    3.正确关闭线程池:
                shutdown():平缓关闭,等待已提交任务完成
                shutdownNow():立即关闭,尝试中断正在执行的任务
    4.处理异常:
                在线程池中执行的任务异常不会直接抛出到主线程,需要在任务内部捕获或通过 Future 获取。
    5.ForkJoinPool 与普通线程池的本质区别:
                工作方式:
                    普通线程池是 "生产者 - 消费者" 模式,而 ForkJoinPool 采用 "工作窃取"(Work-Stealing)算法,空闲线程会主动获取其他线程的任务执行
                任务类型:
                    ForkJoinPool 适合可递归分解的任务(RecursiveTask/RecursiveAction),普通线程池适合独立的原子任务
                并行效率:
                    对于计算密集型的大型任务,ForkJoinPool 能更好地利用多核 CPU  
                计算密集型任务优先考虑 ForkJoinPool,其并行处理能力优于普通线程池
  
    6.线程管理策略差异:
                FixedThreadPool 保持固定线程数,避免频繁创建线程的开销
                CachedThreadPool 线程数弹性变化,适合短任务但可能创建大量线程
                ScheduledThreadPool 有专门的调度机制,支持延迟和周期性执行

通过合理使用线程池,可以有效提升 Java 应用的并发处理能力和资源利用率。

ThreadPoolExecutor  创建线程池

            在 Java 中,ThreadPoolExecutor 是创建和管理线程池的核心类,位于 java.util.concurrent 包下。它提供了高度可配置的线程池实现,
允许你根据需求定制线程池的各种参数。

ThreadPoolExecutor 的示例代码:

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 线程池核心参数设置
        int corePoolSize = 3;          // 核心线程数
        int maximumPoolSize = 5;       // 最大线程数
        long keepAliveTime = 60;       // 非核心线程空闲超时时间
        TimeUnit unit = TimeUnit.SECONDS; // 超时时间单位
        // 任务队列,用于存储等待执行的任务
        ArrayBlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(10);
        
        // 创建线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            corePoolSize,
            maximumPoolSize,
            keepAliveTime,
            unit,
            workQueue
        );
        
        // 提交任务到线程池
        for (int i = 0; i < 8; i++) {
            final int taskId = i;
            executor.submit(() -> {
                try {
                    System.out.println("任务 " + taskId + " 开始执行,线程名:" + Thread.currentThread().getName());
                    // 模拟任务执行时间
                    Thread.sleep(1000);
                    System.out.println("任务 " + taskId + " 执行完毕");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    e.printStackTrace();
                }
            });
        }
        
        // 关闭线程池
        executor.shutdown();
        try {
            // 等待所有任务完成或超时
            if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
                // 超时后强制关闭
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
        }
        System.out.println("所有任务处理完毕,线程池已关闭");
    }
}
线程池核心参数说明:
    (1) corePoolSize:核心线程数,线程池始终保持的线程数量
    (2) maximumPoolSize:最大线程数,线程池允许创建的最大线程数量
    (3) keepAliveTime:当线程数超过核心线程数时,多余的空闲线程的存活时间
    (4) unit:keepAliveTime 的时间单位
    (5) workQueue:任务队列,用于存储等待执行的任务
线程池工作流程:
    1.当提交任务时,若当前线程数小于核心线程数,会创建新线程执行任务
    2.若当前线程数等于核心线程数,新任务会被加入任务队列等待
    3.若任务队列已满,且当前线程数小于最大线程数,会创建新线程执行任务
    4.若任务队列已满且线程数已达最大值,会触发拒绝策略(默认抛出异常)
常用任务队列:
    1.ArrayBlockingQueue:基于数组的有界阻塞队列
    2.LinkedBlockingQueue:基于链表的阻塞队列,可设置边界
    3.SynchronousQueue:不存储元素的阻塞队列,每个插入操作必须等待对应的删除操作
在实际开发中,也可以使用 Executors 工具类快速创建线程池,但推荐手动创建 ThreadPoolExecutor 以明确配置参数,避免资源耗尽风险。

异步线程执行实现

        在 Java 中实现异步线程执行,最常用的方式是结合线程池(ThreadPoolExecutor)和 CompletableFuture(Java 8+ 引入),
它们提供了强大的异步编程能力,支持链式调用、结果组合等高级特性。

典型的 Java 异步线程执行实现方式:

public class JavaAsyncDemo {

    // 定义线程池(推荐复用,避免频繁创建)
    private static final ExecutorService executor = new ThreadPoolExecutor(
        4,  // 核心线程数
        8,  // 最大线程数
        60, // 空闲线程存活时间
        TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(100), // 任务队列
        new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
    );

    public static void main(String[] args) throws Exception {
        System.out.println("主线程开始: " + Thread.currentThread().getName());

        // 方式1: 基础异步执行(无返回值)
        executor.execute(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("异步任务1完成(无返回值)");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // 方式2: 带返回值的异步执行(Future)
        Future<String> future = executor.submit(() -> {
            Thread.sleep(1500);
            return "异步任务2的结果";
        });

        // 方式3: 高级异步编程(CompletableFuture)
        CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
                return "原始数据";
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, executor)
        // 异步处理结果(链式调用)
        .thenApplyAsync(data -> {
            System.out.println("处理中: " + data);
            return data + " -> 处理后的数据";
        }, executor)
        // 异步消费结果
        .thenAcceptAsync(result -> {
            System.out.println("最终结果: " + result);
        }, executor);

        // 主线程继续执行其他操作(非阻塞)
        System.out.println("主线程继续执行...");
        Thread.sleep(500);

        // 获取方式2的结果(会阻塞直到结果返回)
         System.out.println(future.get());
        // 等待方式3完成
        cf.get();

        // 关闭线程池
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);
        System.out.println("主线程结束");
    }    
}
核心实现说明
    1.线程池(ExecutorService):
        (1)是异步执行的基础,负责管理线程资源
        (2)推荐手动创建 ThreadPoolExecutor 而非使用 Executors 工具类,便于控制资源
        (3)心参数(核心线程数、最大线程数、队列等)需根据业务场景配置
    2.CompletableFuture 核心优势:
        (1)链式调用:通过 thenApply、thenAccept 等方法实现结果的流水线处理
        (2)异步组合:支持多个异步任务的并行 / 串行组合(thenCombine、allOf 等)
        (3)异常处理:提供 exceptionally、handle 等方法处理异步任务中的异常
        (4)非阻塞获取结果:可通过 whenComplete 在结果就绪时自动处理,避免阻塞
    3.常见使用场景:
        (1)I/O 密集型操作(数据库查询、网络请求、文件读写)
        (2)需要并行处理的任务(如批量数据处理)
        (3)需避免主线程阻塞的场景(如 GUI 程序、服务器请求处理)
使用时需注意:线程池需要正确关闭(shutdown()),避免资源泄漏;
对于长时间运行的异步任务,要做好超时控制(get(long timeout, TimeUnit unit))。
public class JavaAsyncDemo {

    // 定义线程池(推荐复用,避免频繁创建)
    private static final ExecutorService executor = new ThreadPoolExecutor(
            4,  // 核心线程数
            8,  // 最大线程数
            60, // 空闲线程存活时间
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100), // 任务队列
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
    );

    public static void main(String[] args) throws Exception {
        System.out.println("主线程开始: " + Thread.currentThread().getName());

        // 方式1: 基础异步执行(无返回值)
        executor.execute(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("异步任务1完成(无返回值)");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // 方式2: 带返回值的异步执行(Future)
        Future<String> future = executor.submit(() -> {
            Thread.sleep(1500);
            return "异步任务2的结果";
        });

        // 方式3: 高级异步编程(CompletableFuture)
        CompletableFuture<Void> cf = CompletableFuture.supplyAsync(() -> {
                    try {
                        Thread.sleep(2000);
                        return "原始数据";
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }, executor)
                // 异步处理结果(链式调用)
                .thenApplyAsync(data -> {
                    System.out.println("处理中: " + data);
                    return data + " -> 处理后的数据";
                }, executor)
                // 异步消费结果
                .thenAcceptAsync(result -> {
                    System.out.println("最终结果: " + result);
                }, executor);

        // 主线程继续执行其他操作(非阻塞)
        System.out.println("主线程继续执行...");
        Thread.sleep(500);

        // 获取方式2的结果(会阻塞直到结果返回)
        System.out.println(future.get());

        // 等待方式3完成
        cf.get();

        // 关闭线程池
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);
        System.out.println("主线程结束");

        //默认使用forkJoinThreadPool
        CompletableFuture<String> futureTask = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
                return "原始数据,默认使用forkJoinThreadPool";
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });

        // 方式1: get() - 阻塞等待结果(无超时)
        try {
            String result1 = futureTask.get();
            System.out.println("方式1结果: " + result1);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        // 方式2: get(long timeout, TimeUnit unit) - 带超时的阻塞等待
        try {
            // 超时设置为3秒
            String result2 = futureTask.get(3, TimeUnit.SECONDS);
            System.out.println("方式2结果: " + result2);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            e.printStackTrace();
        }
        // 方式3: join() - 阻塞等待(无超时,只抛出未检查异常)
        try {
            String result3 = futureTask.join();
            System.out.println("方式3结果: " + result3);
        } catch (RuntimeException e) { // supplyAsync中抛出的RuntimeException会被捕获
            e.printStackTrace();
        }

        // 方式4: 非阻塞回调处理(推荐)
        futureTask.whenComplete((result, ex) -> {
            if (ex == null) {
                System.out.println("方式4结果: " + result);
            } else {
                System.out.println("方式4出错: " + ex.getMessage());
            }
        });

        // 等待回调执行完成(实际业务中无需此步骤,这里仅为演示)
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

<think>我们正在讨论如何在Java中使用ForkJoinPool嵌套线程池。嵌套线程池指的是在一个ForkJoinPool的任务中再提交任务到另一个线程池(可能是另一个ForkJoinPool,也可能是其他类型的线程池,如ThreadPoolExecutor)。需要注意的是,在ForkJoinPool的任务中提交新任务到同一个ForkJoinPool可能会导致工作线程被阻塞(因为等待子任务完成),从而可能引起性能问题(如线程饥饿)。因此,通常建议避免在ForkJoinPool的任务中再提交任务到同一个ForkJoinPool,但可以提交到不同的线程池。 以下是一个示例,展示如何在ForkJoinPool的任务中使用另一个线程池(比如一个普通ThreadPoolExecutor)来执行嵌套任务: 步骤: 1. 创建第一个ForkJoinPool(作为外层线程池)。 2. 在提交给外层ForkJoinPool的任务中,我们创建一个不同的线程池(例如,一个固定大小的ThreadPoolExecutor)来执行内部任务。 3. 注意:为了避免死锁资源耗尽,要确保内部线程池的大小是有限的,并且不会过度占用系统资源。 示例代码: ```java import java.util.concurrent.*; public class NestedPoolsExample { public static void main(String[] args) throws Exception { // 外层ForkJoinPool ForkJoinPool forkJoinPool = new ForkJoinPool(); // 提交一个任务到外层ForkJoinPool forkJoinPool.submit(() -> { System.out.println("Outer task running in " + Thread.currentThread().getName()); // 创建一个内部线程池(这里使用固定大小的线程池) ExecutorService innerExecutor = Executors.newFixedThreadPool(2); // 提交一些任务到内部线程池 Future<?> future1 = innerExecutor.submit(() -> { System.out.println("Inner task 1 running in " + Thread.currentThread().getName()); }); Future<?> future2 = innerExecutor.submit(() -> { System.out.println("Inner task 2 running in " + Thread.currentThread().getName()); }); // 等待内部任务完成 try { future1.get(); future2.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } finally { innerExecutor.shutdown(); // 关闭内部线程池 } }).get(); // 等待外层任务完成 forkJoinPool.shutdown(); // 关闭外层线程池 } } ``` 注意:在这个例子中,外层任务在ForkJoinPool中执行,然后它创建了一个独立的内部线程池ThreadPoolExecutor)来执行两个内部任务。外层任务等待内部任务完成后再结束。 但是,如果我们需要在ForkJoinPool的任务中再使用ForkJoinPool(即嵌套ForkJoinPool),则需要格外小心,因为ForkJoinPool的工作线程在等待子任务完成时可能会被阻塞,如果所有线程都在等待,就会导致死锁。因此,通常不建议嵌套使用同一个ForkJoinPool(尤其是默认的common池),但可以创建不同的ForkJoinPool实例。 示例:嵌套使用两个不同的ForkJoinPool实例 ```java import java.util.concurrent.*; public class NestedForkJoinPools { public static void main(String[] args) throws Exception { // 外层ForkJoinPool ForkJoinPool outerPool = new ForkJoinPool(); outerPool.submit(() -> { System.out.println("Outer task in " + Thread.currentThread().getName()); // 内层ForkJoinPool(使用不同的实例) ForkJoinPool innerPool = new ForkJoinPool(); innerPool.submit(() -> { System.out.println("Inner task in " + Thread.currentThread().getName()); }).join(); // 等待内层任务完成 innerPool.shutdown(); // 关闭内层线程池 }).join(); // 等待外层任务完成 outerPool.shutdown(); } } ``` 注意:这里我们使用了两个独立的ForkJoinPool实例(outerPoolinnerPool)。外层任务提交到outerPool,内层任务提交到innerPool。这样就不会因为outerPool的工作线程等待innerPool的任务而阻塞outerPool的所有线程(因为innerPool有自己的工作线程)。 然而,创建多个ForkJoinPool实例可能会消耗更多系统资源,因此需要根据实际情况权衡。 另外,在ForkJoinPool的任务中,我们也可以使用ForkJoinTask(如RecursiveAction)来分解子任务,这是ForkJoinPool的常规用法,并不属于嵌套线程池,而是同一个线程池内的任务分解。 总结: - 嵌套线程池通常指的是在一个线程池的任务中提交任务到另一个线程池。 - 可以使用ForkJoinPoolThreadPoolExecutor的组合,也可以使用多个ForkJoinPool实例(避免使用同一个实例嵌套提交,以免死锁)。 - 需要谨慎管理线程池的生命周期,及时关闭。 引用说明: 在ForkJoinPool的任务中创建另一个线程池(如ThreadPoolExecutor)来执行内部任务,可以避免同一个ForkJoinPool内的嵌套问题[^1][^4]。而嵌套使用不同的ForkJoinPool实例也是可行的,但要注意资源管理[^4]。 根据以上内容,我们可以生成相关问题。 相关问题: 1. 在ForkJoinPool中嵌套使用同一个ForkJoinPool实例会有什么问题? 2. 如何避免嵌套线程池导致的死锁? 3. 除了ForkJoinPool,还有哪些线程池适合嵌套使用? 4. 嵌套线程池时如何管理线程池的生命周期?</think>### 在 Java 中使用 ForkJoinPool 嵌套线程池的方法 在 Java 中嵌套使用 `ForkJoinPool` 需要特别注意线程池的层次结构任务分解策略,以避免死锁资源竞争问题。以下是具体实现方法示例: #### 核心实现方法 1. **分层线程池设计**: - 外层线程池处理粗粒度任务 - 内层线程池处理细粒度子任务 - 使用 `RecursiveTask`/`RecursiveAction` 实现任务分解 2. **避免共享线程池**: ```java // 创建独立的线程池实例 ForkJoinPool outerPool = new ForkJoinPool(4); // 外层池 ForkJoinPool innerPool = new ForkJoinPool(2); // 内层池 ``` 3. **任务提交策略**: ```java outerPool.submit(() -> { // 外层任务中提交到内层池 innerPool.submit(() -> { // 内层任务逻辑 }); }); ``` #### 完整示例代码 ```java import java.util.concurrent.*; public class NestedForkJoinDemo { // 内层任务类 static class InnerTask extends RecursiveTask<Integer> { private final int n; InnerTask(int n) { this.n = n; } @Override protected Integer compute() { if (n <= 1) return n; InnerTask f1 = new InnerTask(n - 1); f1.fork(); InnerTask f2 = new InnerTask(n - 2); return f2.compute() + f1.join(); // 递归计算[^5] } } // 外层任务类 static class OuterTask extends RecursiveTask<Integer> { private final int[] data; OuterTask(int[] data) { this.data = data; } @Override protected Integer compute() { if (data.length <= 2) { // 小任务直接计算 return Arrays.stream(data).sum(); } // 分解任务 int mid = data.length / 2; OuterTask left = new OuterTask(Arrays.copyOfRange(data, 0, mid)); OuterTask right = new OuterTask(Arrays.copyOfRange(data, mid, data.length)); left.fork(); return right.compute() + left.join(); } } public static void main(String[] args) { // 创建嵌套线程池 ForkJoinPool outerPool = new ForkJoinPool(4); ForkJoinPool innerPool = new ForkJoinPool(2); int[] data = IntStream.range(1, 100).toArray(); // 提交外层任务 outerPool.submit(() -> { // 执行外层分解 OuterTask outerTask = new OuterTask(data); outerTask.fork(); // 在内层池执行子任务 innerPool.submit(() -> { System.out.println("内层任务结果: " + new InnerTask(10).compute()); }); return outerTask.join(); }).join(); // 等待外层任务完成[^1] // 关闭线程池 outerPool.shutdown(); innerPool.shutdown(); } } ``` #### 关键注意事项 1. **避免死锁**: - 确保内层任务不会阻塞外层线程 - 使用 `join()` 时注意任务依赖关系 ```java // 正确写法:先fork再compute left.fork(); return right.compute() + left.join(); ``` 2. **资源隔离**: - 为不同层级使用独立线程池 - 限制各层线程池大小 ```java // 根据CPU核心数设置 int cores = Runtime.getRuntime().availableProcessors(); ForkJoinPool outer = new ForkJoinPool(cores / 2); ForkJoinPool inner = new ForkJoinPool(cores / 4); ``` 3. **任务粒度控制**: - 外层处理大块数据分解 - 内层处理精细计算 - 设置合理的阈值避免过度分解 4. **异常处理**: ```java try { innerPool.submit(...).get(); } catch (InterruptedException | ExecutionException e) { // 处理内层任务异常 } ``` #### 适用场景 1. **多层递归算法**:如复杂数学计算、图像处理 2. **混合并行任务**:CPU密集型 + I/O密集型组合 3. **分级数据处理**:先粗粒度分区再细粒度计算 > **重要提示**:嵌套线程池会增加系统复杂性,仅在单层线程池无法满足性能需求时使用。对于简单任务,优先使用单层 `ForkJoinPool` 或 `CompletableFuture`[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值