MST

星途 面试题库

面试题:Java AIO异步线程池大小动态调整的策略实现

请设计并实现一个Java AIO异步线程池大小动态调整的策略。当系统负载较高时,适当增加线程池大小;当负载较低时,减少线程池大小。要求说明你选择的负载衡量指标,给出关键代码片段并解释其工作原理。
34.0万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

负载衡量指标选择

选择CPU使用率作为负载衡量指标。因为CPU使用率能够直观反映系统当前处理任务的繁忙程度,较高的CPU使用率通常意味着系统负载较高,需要更多线程来处理任务;较低的CPU使用率则表示系统负载较低,可以适当减少线程数量以节省资源。

关键代码片段

import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class AIOThreadPoolDynamicAdjustment {
    private static final int CORE_POOL_SIZE = 5;
    private static final int MAX_POOL_SIZE = 50;
    private static final long KEEP_ALIVE_TIME = 10L;
    private static final ExecutorService executorService = Executors.newFixedThreadPool(CORE_POOL_SIZE);
    private static final OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();

    public static void main(String[] args) {
        Thread monitorThread = new Thread(() -> {
            while (true) {
                double cpuUsage = getSystemCpuUsage();
                ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService;
                if (cpuUsage > 0.7) {
                    if (threadPoolExecutor.getPoolSize() < MAX_POOL_SIZE) {
                        threadPoolExecutor.setCorePoolSize(threadPoolExecutor.getCorePoolSize() + 1);
                        threadPoolExecutor.setMaximumPoolSize(threadPoolExecutor.getMaximumPoolSize() + 1);
                    }
                } else if (cpuUsage < 0.3 && threadPoolExecutor.getPoolSize() > CORE_POOL_SIZE) {
                    threadPoolExecutor.setCorePoolSize(threadPoolExecutor.getCorePoolSize() - 1);
                    threadPoolExecutor.setMaximumPoolSize(threadPoolExecutor.getMaximumPoolSize() - 1);
                }
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        monitorThread.setDaemon(true);
        monitorThread.start();

        // 模拟任务提交
        for (int i = 0; i < 100; i++) {
            executorService.submit(() -> {
                // 模拟任务执行
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }

    private static double getSystemCpuUsage() {
        try {
            Method method = osBean.getClass().getMethod("getSystemCpuLoad");
            method.setAccessible(true);
            Double cpuUsage = (Double) method.invoke(osBean);
            if (cpuUsage == -1.0) {
                return 0.0;
            }
            return cpuUsage;
        } catch (Exception e) {
            e.printStackTrace();
            return 0.0;
        }
    }
}

代码工作原理

  1. 获取CPU使用率getSystemCpuUsage 方法通过反射调用 OperatingSystemMXBeangetSystemCpuLoad 方法获取系统CPU使用率。该方法返回值范围为0.0到1.0,代表CPU使用率的百分比。
  2. 线程池监控与调整:在 main 方法中启动一个守护线程 monitorThread,该线程每隔5秒检查一次系统CPU使用率。
    • 如果CPU使用率大于70% (cpuUsage > 0.7),并且当前线程池大小小于最大线程池大小 (threadPoolExecutor.getPoolSize() < MAX_POOL_SIZE),则增加线程池的核心线程数和最大线程数各1。
    • 如果CPU使用率小于30% (cpuUsage < 0.3),并且当前线程池大小大于核心线程数 (threadPoolExecutor.getPoolSize() > CORE_POOL_SIZE),则减少线程池的核心线程数和最大线程数各1。
  3. 线程池初始化:使用 Executors.newFixedThreadPool(CORE_POOL_SIZE) 初始化一个固定大小的线程池,初始核心线程数为 CORE_POOL_SIZE。在实际应用中,可以根据具体需求调整 CORE_POOL_SIZEMAX_POOL_SIZE 等参数。
  4. 任务提交:通过 executorService.submit 方法模拟向线程池提交任务,任务模拟执行1秒。

通过这种方式实现了AIO异步线程池大小根据系统CPU使用率动态调整的策略。