根据CPU和内存使用情况调整线程池的Java Executor

5

我的应用程序使用Executor为大量任务提供线程池。通过分析和基准测试,我已经确定当每个核心有多个线程时,我的应用程序运行速度最快。一个很好的启发式法则是从每个核心开始使用4个线程,直到达到>90%的CPU或>90%的RAM。

是否有可用的Executor可以自动处理这个问题?即自动使用N个线程每个核心(不仅仅是一个),或者更理想的是,根据CPU和RAM使用情况限制线程池大小?

如果没有 - 我该如何以编程方式确定核心数?

2个回答

2
Runtime.availableProcessors()

Javadoc:

返回 Java 虚拟机可用的处理器数量。这个值在虚拟机调用期间可能会发生变化。因此,对可用处理器数量敏感的应用程序应该定期轮询此属性,并相应地调整资源使用。


2
一种方法是使用 ThreadPoolExecutor,其中 核心大小 为1,启动 最大池大小 为4,然后根据内存和CPU使用情况动态调整最大池大小。
我认为更大的问题是如何测量内存使用和CPU负载。内存使用很容易:
public double memUsageRatio() {
  Runtime r = Runtime.getRuntime();
  return (double) (r.totalMemory() - r.freeMemory()) / r.maxMemory();
}

关于 CPU 负载,它可能会更具问题,这取决于您运行的平台。在 Linux 上,您可以使用以下命令:
ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage();

这个函数返回最近一分钟的系统平均负载。不幸的是,在Windows上,该方法总是返回-1。过去,我曾用给定时间间隔内系统平均负载的近似值来替换它,通过计算所有线程的CPU时间总和除以所有处理器的所有经过时间总和。这只是一个近似值,但在大多数情况下效果还不错。
import java.lang.management.*;

public class CPUUsageCollector implements Runnable {
  private final static long INTERVAL = 1000L; // polling interval in ms
  private long totalCpuTime = 0L; // total CPU time in millis
  private double load = 0d; // average load over the interval
  ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
  boolean stopped = false;

  @Override
  public void run() {
    try {
      while (!isStopped()) {
        long start = System.currentTimeMillis();
        long[] ids = threadMXBean.getAllThreadIds();
        long time = 0L;
        for (long id: ids) {
          long l = threadMXBean.getThreadCpuTime(id);
          if (l >= 0L) time += l;
        }
        long newCpuTime = time / 1000000L;
        synchronized(this) {
          long oldCpuTime = totalCpuTime;
          totalCpuTime = newCpuTime;
          // load = CPU time difference / sum of elapsed time for all CPUs
          load = (double) (newCpuTime - oldCpuTime) / 
           (double) (INTERVAL * Runtime.getRuntime().availableProcessors());
        }
        long sleepTime = INTERVAL - (System.currentTimeMillis() - start);
        goToSleep(sleepTime <= 0L ? INTERVAL : sleepTime);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public synchronized double getLoad() {
    return load;
  }

  public synchronized void goToSleep(final long time) {
    try {
      wait(time);
    } catch(InterruptedException e) {
      e.printStackTrace();
    }
  }

  public synchronized boolean isStopped() {
    return stopped;
  }

  public synchronized void setStopped(final boolean stopped) {
    this.stopped = stopped;
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接