在壓力測試、資源隔離驗證、容器配額測試等場景下,需要程式以特定佔用率持續運行。本文遞進展示三種實現:固定佔用率、可配比例、正弦波動態曲線,並分析精度限制與生產級改進方向。
public class CpuBurnerV1 {
public static void main(String[] args) throws Exception {
while (true) {
// 空循環消耗 CPU
for (int i = 0; i < 96_000_000; i++) ;
// 休眠釋放 CPU
Thread.sleep(10);
}
}
}
缺點:循環次數與硬件強綁定,不同 CPU 主頻、架構下佔用率漂移極大。
public class CpuBurnerV2 {
private static final int BUSY_MS = 10; // 忙碌毫秒數
private static final int IDLE_MS = 10; // 空閒毫秒數 (50% 佔用)
public static void main(String[] args) throws Exception {
while (true) {
long start = System.currentTimeMillis();
// 燒 CPU 直到達到 busy 時間
while (System.currentTimeMillis() - start < BUSY_MS) ;
Thread.sleep(IDLE_MS);
}
}
}
原理:在週期 T = BUSY + IDLE 內,佔用率 ≈ BUSY / T。
缺點:Thread.sleep 精度受限於 OS 調度器 (通常 10-15ms),高佔用率場景誤差大。
public class CpuBurnerV3 {
private static final double SPLIT = 0.01; // 角度步長
private static final int COUNT = (int) (2 / SPLIT); // 2π 週期采樣點數
private static final int INTERVAL_MS = 200; // 控制週期總長
private static final int HALF = INTERVAL_MS / 2;
public static void main(String[] args) throws Exception {
long[] busy = new long[COUNT];
long[] idle = new long[COUNT];
// 預計算正弦波佔用分布
for (int i = 0; i < COUNT; i++) {
double radian = i * SPLIT * Math.PI;
busy[i] = (long) (HALF + Math.sin(radian) * HALF);
idle[i] = INTERVAL_MS - busy[i];
}
int idx = 0;
while (true) {
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < busy[idx]) ;
Thread.sleep(idle[idx]);
idx = (idx + 1) % COUNT;
}
}
}

| 因素 | 影響 | 緩解方案 |
|---|---|---|
| Thread.sleep 最小粒度 | Windows ~15ms, Linux ~1ms (高精度定時器) | 使用 LockSupport.parkNanos 或 JNI 調用 nanosleep |
| JIT 編譯優化 | 空循環可能被優化消除 | 加 volatile 偽變量、或計算哈希值防止優化 |
| GC 停頓 | 長時間運行觸發 Full GC 導致佔用率驟降 | -Xms=Xmx 固定堆、使用 ZGC/Shenandoah 低延遲 GC |
| 多核調度 | 單線程僅佔用 1 核,整體佔用率 = 目標 / 核心數 | 啟動 N 個線程,每核一個,配合 Taskset 綁核 |
stress-ng -c 2 -l 50 --timeout 60s (Linux 原生工具,支援佔用率、溫度、I/O 多維壓力)docker run --cpus="1.5" ... 容器級硬限制,驗證應用在配額下表現代碼級 CPU 控制本質是「用戶態自旋 + 內核態休眂」協作,受限於 OS 調度器語義,無法達到硬實時精度。工程實踐中應優先選擇系統級工具,代碼實現僅作為輕量級輔助或教學用途。