MST
星途 面试题库

面试题:Java线程池最大线程数在动态场景下的自适应调整策略

在一个实时监控流量的Java应用中,流量波动较大,任务执行时间也长短不一。请设计一套方案,使线程池的最大线程数能够根据实时的系统资源使用情况(如CPU利用率、内存使用率)以及任务队列的堆积情况动态自适应调整,并给出关键代码示例及实现思路。
24.2万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 获取系统资源使用情况:利用com.sun.management.OperatingSystemMXBean获取CPU利用率和内存使用率。
  2. 监控任务队列堆积情况:通过ThreadPoolExecutorgetQueue().size()方法获取任务队列当前的任务数量。
  3. 动态调整线程池大小:根据系统资源和任务队列堆积情况,设定调整策略,动态改变线程池的最大线程数。

关键代码示例

import com.sun.management.OperatingSystemMXBean;
import java.lang.management.ManagementFactory;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class AdaptiveThreadPool {

    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 TimeUnit TIME_UNIT = TimeUnit.SECONDS;
    private static final int QUEUE_CAPACITY = 100;

    private final ThreadPoolExecutor executor;
    private final OperatingSystemMXBean osBean;

    public AdaptiveThreadPool() {
        BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>(QUEUE_CAPACITY);
        executor = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAX_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TIME_UNIT,
                taskQueue);
        osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
        startMonitor();
    }

    private void startMonitor() {
        Thread monitorThread = new Thread(() -> {
            while (true) {
                try {
                    double cpuUsage = osBean.getSystemCpuLoad();
                    long memoryUsage = osBean.getTotalPhysicalMemorySize() - osBean.getFreePhysicalMemorySize();
                    int queueSize = executor.getQueue().size();

                    // 调整策略示例:
                    // 如果CPU利用率低且任务队列堆积,增加线程数
                    if (cpuUsage < 0.5 && queueSize > QUEUE_CAPACITY * 0.7) {
                        if (executor.getMaximumPoolSize() < MAX_POOL_SIZE) {
                            executor.setMaximumPoolSize(executor.getMaximumPoolSize() + 5);
                        }
                    }
                    // 如果CPU利用率高且任务队列无堆积,减少线程数
                    else if (cpuUsage > 0.8 && queueSize < QUEUE_CAPACITY * 0.3) {
                        if (executor.getMaximumPoolSize() > CORE_POOL_SIZE) {
                            executor.setMaximumPoolSize(executor.getMaximumPoolSize() - 5);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        monitorThread.setDaemon(true);
        monitorThread.start();
    }

    public void submitTask(Runnable task) {
        executor.submit(task);
    }

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

使用示例

public class Main {
    public static void main(String[] args) {
        AdaptiveThreadPool threadPool = new AdaptiveThreadPool();
        for (int i = 0; i < 200; i++) {
            int taskNumber = i;
            threadPool.submitTask(() -> {
                System.out.println("Task " + taskNumber + " is running on thread " + Thread.currentThread().getName());
                try {
                    Thread.sleep((long) (Math.random() * 1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        threadPool.shutdown();
    }
}

上述代码中:

  1. AdaptiveThreadPool类构造函数初始化线程池,并获取OperatingSystemMXBean实例。
  2. startMonitor方法启动一个守护线程,定期(每5秒)获取系统资源使用情况和任务队列大小,并根据设定策略调整线程池最大线程数。
  3. submitTask方法用于向线程池提交任务。
  4. shutdown方法用于关闭线程池。

Main类中,模拟向线程池提交200个任务,每个任务随机执行一段时间。