MST

星途 面试题库

面试题:Java CompletableFuture thenAccept在高并发且资源受限场景下的优化应用

在一个高并发的系统中,有大量的CompletableFuture任务,每个任务在执行完成后通过thenAccept进行结果消费。由于系统资源(如内存、数据库连接数等)有限,可能会出现资源耗尽的情况。请你提出一种基于CompletableFuture thenAccept的优化策略,以确保系统在高并发下的稳定性和性能,详细阐述策略的原理,并给出关键代码示例以及性能测试的思路。
49.8万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

优化策略及原理

  1. 使用线程池控制并发度:通过创建固定大小的线程池来执行CompletableFuture任务。这样可以限制同时执行的任务数量,避免过多任务同时竞争系统资源,从而防止资源耗尽。例如,数据库连接数有限时,过多任务同时尝试获取连接会导致连接池耗尽。
  2. 资源管理:在thenAccept中进行资源的合理管理,比如及时释放数据库连接等资源,避免资源长时间被占用。

关键代码示例

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class CompletableFutureOptimization {
    private static final ExecutorService executorService = Executors.newFixedThreadPool(10);
    private static final AtomicInteger counter = new AtomicInteger();

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            CompletableFuture.supplyAsync(() -> {
                // 模拟任务执行
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return counter.incrementAndGet();
            }, executorService)
           .thenAccept(result -> {
                // 模拟结果消费和资源管理
                System.out.println("Processed result: " + result);
                // 例如这里可以添加释放数据库连接等资源管理的代码
            });
        }

        executorService.shutdown();
        try {
            if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                executorService.shutdownNow();
                if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                    System.err.println("Pool did not terminate");
                }
            }
        } catch (InterruptedException ie) {
            executorService.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}

性能测试思路

  1. 指标设定
    • 吞吐量:统计单位时间内完成的任务数量,通过记录开始时间和结束时间以及完成的任务总数来计算。
    • 响应时间:记录每个任务从提交到完成消费的时间,可通过在任务开始和结束时记录时间戳计算。
    • 资源使用率:监控内存、CPU使用率以及数据库连接数等资源的使用情况,例如使用java.lang.management包获取内存和CPU信息,数据库连接池提供的监控工具获取连接使用情况。
  2. 测试场景
    • 不同并发数:从低并发(如10个任务)逐渐增加到高并发(如1000个任务),观察系统在不同并发压力下的性能指标。
    • 不同资源限制:例如改变线程池大小、减少数据库连接数等,测试系统在资源受限情况下的性能表现。
  3. 工具使用
    • JMH(Java Microbenchmark Harness):用于微基准测试,精确测量代码片段的性能。
    • JMeter:用于模拟高并发场景,对系统整体性能进行测试。