JAVA CPU控制程序【Linux版】
背景资源紧张的大环境下懂的都懂。实现这个目标我们不需要任何第三方库使用JDK原生的Runtime类即可获取CPU核心数并利用数学计算控制线程的“忙碌”与“休眠”的比例从而达到精确控制CPU使用率的目的控制的是整体利用率不是这个程序的这点很重要。思路开发一个纯 Java、无需第三方 Jar 包、在Linux环境下运行的程序能够将服务器的总 CPU 使用率精准控制在指定值如 80%并持续运行指定时间。获取核心数使用Runtime.getRuntime().availableProcessors()。创建线程根据核心数创建对应数量的线程确保每个核心都有一个线程在工作。计算占比为了达到 80% 的使用率我们需要让线程在一个总周期内80% 的时间在执行计算空转20% 的时间在休眠。执行控制记录开始时间。执行高强度的空运算。如果运行时间超过了设定的“工作时间”例如 80ms则休眠剩余的时间例如 20ms。打印输出信息操作直接上源代码无侵入使用的都是JDK自带的工具类不会引入漏洞另仅消耗CPU内存几乎不耗。CpuLoadSimulator.javaimport java.io.BufferedReader; import java.io.InputStreamReader; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; public class CpuLoadSimulator { private static volatile boolean isRunning false; private static double TARGET_CPU_LOAD 80.0; private static int RUN_TIME_SECONDS 60; // --- 优化参数 --- private static final long BIG_STEP_MS 5; // 大调整步长 (误差大时用) private static final long SMALL_STEP_MS 1; // 小调整步长 (微调时用) private static final double DEAD_ZONE 2.0; // 死区范围 (/- 2.0% 内不调整) public static void main(String[] args) throws InterruptedException { // 1. 参数解析 if (args.length 0) { try { TARGET_CPU_LOAD Double.parseDouble(args[0]); if(TARGET_CPU_LOAD1) TARGET_CPU_LOAD1; if(TARGET_CPU_LOAD100) TARGET_CPU_LOAD100; } catch (Exception e) {} } if (args.length 1) { try { RUN_TIME_SECONDS Integer.parseInt(args[1]); if(RUN_TIME_SECONDS1) RUN_TIME_SECONDS1; } catch (Exception e) {} } // 2. 初始化 int coreCount Runtime.getRuntime().availableProcessors(); System.out.println(CPU 核心数: coreCount); System.out.println(目标负载: TARGET_CPU_LOAD %); System.out.println(运行时间: RUN_TIME_SECONDS 秒); String osName System.getProperty(os.name).toLowerCase(); if (!osName.contains(linux)) { System.err.println(错误仅支持 Linux 系统。); return; } // 3. 启动工作线程 ListThread threads new ArrayList(); final SharedSleepTime sharedSleepTime new SharedSleepTime(100L); // 初始 100ms 休眠 for (int i 0; i coreCount; i) { Thread worker new Thread(() - { while (!isRunning) { Thread.yield(); } while (isRunning) { long startTime System.currentTimeMillis(); long currentSleep sharedSleepTime.get(); long workTarget 100 - currentSleep; while (isRunning (System.currentTimeMillis() - startTime) workTarget) { } if (isRunning currentSleep 0) { try { Thread.sleep(currentSleep); } catch (Exception e) { break; } } } }); worker.setName(CpuWorker- i); threads.add(worker); worker.start(); } Thread.sleep(500); isRunning true; System.out.println(线程已就绪开始软启动...\n); // 4. 主控循环 int remainingSeconds RUN_TIME_SECONDS; boolean isWarmup true; int warmupCountdown 5; // 预热5秒 // --- 新增时间格式化 --- SimpleDateFormat sdf new SimpleDateFormat(HH:mm:ss); while (remainingSeconds 0) { double systemIdle getSystemIdleFromTop(); double currentLoad (systemIdle 0) ? (100.0 - systemIdle) : 100.0; long currentSleep sharedSleepTime.get(); long newSleep currentSleep; String status ; if (isWarmup) { // 软启动逻辑 status 软启动; warmupCountdown--; long targetSleep (long) (100 - TARGET_CPU_LOAD); if (currentSleep targetSleep) { newSleep currentSleep - BIG_STEP_MS; } else { newSleep targetSleep; } if (warmupCountdown 0 systemIdle 0) { isWarmup false; // 预热结束 } } else { // 稳态调节逻辑 status 稳调节; double error currentLoad - TARGET_CPU_LOAD; if (Math.abs(error) DEAD_ZONE) { newSleep currentSleep; } else if (error 0) { newSleep currentSleep (error 5.0 ? BIG_STEP_MS : SMALL_STEP_MS); } else { newSleep currentSleep - (error -5.0 ? BIG_STEP_MS : SMALL_STEP_MS); } if (newSleep 99) newSleep 99; if (newSleep 0) newSleep 0; } sharedSleepTime.set(newSleep); // --- 修改点打印当前时间 --- String currentTime sdf.format(new Date()); System.out.printf(%s [%s] 剩余: %3ds | 当前CPU: %6.2f%% | 目标: %5.1f%% | 休眠: %2dms%n, currentTime, status, remainingSeconds, currentLoad, TARGET_CPU_LOAD, newSleep); Thread.sleep(1000); remainingSeconds--; } System.out.println(\n时间到停止...); isRunning false; for (Thread t : threads) t.join(); System.out.println(程序已退出。); } static class SharedSleepTime { private volatile long ms; public SharedSleepTime(long ms) { this.ms ms; } public long get() { return ms; } public void set(long ms) { this.ms ms; } } private static double getSystemIdleFromTop() { try { Process process Runtime.getRuntime().exec(new String[]{sh, -c, top -b -n 1 | grep \Cpu(s)\ | awk {print $8}}); BufferedReader reader new BufferedReader(new InputStreamReader(process.getInputStream())); String line reader.readLine(); if (line ! null !line.isEmpty()) { return Double.parseDouble(line.replace(%, ).trim()); } process.destroyForcibly(); } catch (Exception e) { } return -1.0; } }代码解析Runtime.getRuntime().availableProcessors():这是 Java 原生方法返回 JVM 可用的逻辑处理器数量。如果你的 CPU 支持超线程这里返回的是线程数例如 8 核 16 线程这里通常返回 16。控制比例 (targetLoad):我们定义了一个100ms的循环周期。如果要 80% 的负载代码逻辑就是跑满 80ms-睡觉 20ms-重复。动态调整我们程序的休眠时间。如果发现 CPU总负载低于 80%\rightarrow→ 程序减少休眠多干活把负载顶上去。如果发现 CPU总负载高于 80%\rightarrow→ 程序增加休眠少干活把负载降下来。这就像汽车的定速巡航当前速慢了就踩油门当前速快了就踩刹车。无论服务器上有没有其他程序在跑它都会通过动态调整自己的算力强行把服务器的总 CPU 使用率“钉”在 80% 左右。3.while ((System.currentTimeMillis() - startTime) workTimeMs):这个while循环内部没有任何实际逻辑这叫做“忙等待”。它会让 CPU 处于满负荷运转状态从而产生负载。4.Thread.sleep(sleepTimeMs):这是让 CPU 闲置的方法。通过控制休眠的长短我们就能控制 CPU 的总体使用率。核心机制如何压测工作线程执行一个没有任何内容的空循环while循环。通过疯狂读取系统时间判断是否该结束循环让 CPU 处于“满负荷空转”状态。如何控速主线程每秒读取一次top命令。如果负载低于目标减少线程的休眠时间多干活。如果负载高于目标增加线程的休眠时间少干活。使用说明java CpuLoadSimulator 40 3040目标使用率30持续多久进阶使用指南编制启动脚本加入定时任务crontab,自动化运行。start.sh#!/bin/bash cd /data/mdm2.0/script nohup /usr/local/jdk/jdk8u462-b08/bin/java CpuLoadSimulator 70 180 nohup.out 21 每隔30分钟执行一次设定目标服务器的CPU利用率70%持续时间3分钟。crontab -l*/30 * * * * /data/mdm2.0/script/start.sh /dev/null效果展示解惑1. 哪块代码在消耗 CPUwhile (isRunning) { long startTime System.currentTimeMillis(); long currentSleep sharedSleepTime.get(); long workTarget 100 - currentSleep; // 这里是消耗 CPU 的地方 while (isRunning (System.currentTimeMillis() - startTime) workTarget) { // 空循环体 } // // 下面是休息不消耗 CPU if (isRunning currentSleep 0) { try { Thread.sleep(currentSleep); } catch (Exception e) { break; } } }2. 它是怎么消耗的这种消耗方式叫做“忙等待”。原理如下疯狂地“询问”时间System.currentTimeMillis()是一个去操作系统读取当前时间的函数。无意义地做数学题程序在while循环里每一毫秒都要执行几十万甚至几百万次读取当前时间。减去开始时间。比较是否到了目标时间。跳回循环开头。不让 CPU 休息因为循环体里没有任何Thread.sleep()或I/O操作CPU 根本没有机会把任务挂起。它必须全神贯注、一刻不停地执行这几行简单的代码。3. 为什么不用更复杂的代码你可能会问“为什么不写个死循环算圆周率3.14159...或者做矩阵乘法来消耗 CPU”简单高效比较时间戳是一个非常轻量级的操作对内存几乎零消耗不会触发 Java 的垃圾回收GC。纯 CPU 压力我们的目的是测试 CPU 负载能力而不是测试计算能力或内存能力。空循环能最大限度地榨干 CPU 的“指令周期”而不受内存带宽的瓶颈影响。4. 稳态控制版- 算法优化思路引入了PID 控制简化版和软启动。改进软启动启动时不让线程立刻满载而是慢慢减少休眠时间平滑爬升到目标负载消除了启动突刺。死区控制设定一个范围如目标 ±2%在此范围内不调整消除了震荡现象。