MST

星途 面试题库

面试题:Java CompletableFuture supplyAsync异步任务创建中线程池的合理配置

在使用CompletableFuture的supplyAsync方法创建异步任务时,涉及到线程池的使用。请阐述线程池参数如何合理配置(如核心线程数、最大线程数、队列容量等),以确保在高并发场景下系统性能最优,并且举例说明如何自定义线程池传递给supplyAsync方法。
15.2万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

线程池参数合理配置

  1. 核心线程数
    • 对于CPU密集型任务,核心线程数一般设置为 CPU核心数 + 1。因为CPU密集型任务主要消耗CPU资源,多一个线程可以在某个线程因偶尔的页缺失等情况阻塞时,让CPU不至于空闲。例如,服务器是8核CPU,核心线程数可设为9。
    • 对于I/O密集型任务,核心线程数可设置为 2 * CPU核心数。因为I/O操作会使线程长时间等待,需要更多线程来利用CPU资源。假设服务器是4核CPU,核心线程数可设为8。
  2. 最大线程数
    • 最大线程数一般应大于等于核心线程数。在高并发场景下,当队列已满,且核心线程都在忙碌时,会创建新线程直到达到最大线程数。但设置过大可能会导致系统资源耗尽,因为每个线程都会占用一定的内存等资源。对于大多数场景,最大线程数可以设置为核心线程数的2倍左右。
  3. 队列容量
    • 如果任务处理速度较快,队列容量可以设置得较小,比如100 - 500。这样能快速触发创建新线程,及时处理任务。
    • 如果任务处理速度较慢,队列容量可以设置得较大,如1000 - 5000,避免过多线程创建导致系统资源耗尽。但过大的队列容量可能会导致任务处理延迟增加。

自定义线程池传递给supplyAsync方法示例

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class CompletableFutureThreadPoolExample {
    public static void main(String[] args) {
        // 自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                5, // 核心线程数
                10, // 最大线程数
                10L, // 线程存活时间
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(100), // 队列容量
                new ThreadFactory() {
                    private final AtomicInteger threadNumber = new AtomicInteger(1);
                    private final ReentrantLock lock = new ReentrantLock();
                    private final Condition notFull = lock.newCondition();
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread t = new Thread(r, "MyThread-" + threadNumber.getAndIncrement());
                        if (t.isDaemon()) {
                            t.setDaemon(false);
                        }
                        if (t.getPriority() != Thread.NORM_PRIORITY) {
                            t.setPriority(Thread.NORM_PRIORITY);
                        }
                        return t;
                    }
                },
                new ThreadPoolExecutor.CallerRunsPolicy());

        CompletableFuture.supplyAsync(() -> {
            // 异步任务逻辑
            System.out.println("执行异步任务");
            return "任务结果";
        }, executor)
       .thenAccept(result -> {
            System.out.println("处理任务结果: " + result);
        });

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

在上述示例中,通过 ThreadPoolExecutor 自定义了一个线程池,并将其传递给 CompletableFuture.supplyAsync 方法,在异步任务执行完毕后,通过 thenAccept 处理任务结果。最后通过 executor.shutdown() 关闭线程池。