在受控電腦上部署後台服務,工作日 17:00–23:25 允許使用,超時強制關機;防止用戶修改系統時間繞過限制;以 Windows Service 形式運行,無界面、難被終止。
┌─────────────────────────────────────┐
│ Windows Service Manager │
│ (JavaService / Procrun / WinSW) │
└──────────────┬──────────────────────┘
│ 啟動 JVM
▼
┌─────────────────────────────────────┐
│ TimerShutDownWindows (主類) │
│ ├─ TimerDetector (監控線程) │
│ │ ├─ 校驗系統時間是否被竄改 │
│ │ ├─ 判斷是否達到關機窗口 │
│ │ └─ 執行 shutdown 命令 │
│ └─ 日誌輸出 │
└─────────────────────────────────────┘
public class TimerShutDownWindows {
// 配置常量
private static final long DETECT_INTERVAL_MS = 5_000;
private static final int ALLOW_START_HOUR = 17; // 17:00
private static final int ALLOW_END_HOUR = 23; // 23:25
private static final int ALLOW_END_MINUTE = 25;
private static final String LOG_FILE = "D:/my_shutdown.log";
private static long lastCheckMs = 0;
private static boolean hasShutdown = false;
public static void main(String[] args) {
new Thread(new TimerDetector(), "Shutdown-Detector").start();
}
static class TimerDetector implements Runnable {
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private PrintWriter log;
@Override public void run() {
initLog();
log("服務啟動:" + sdf.format(new Date()));
while (true) {
if (shouldForceShutdown()) {
executeShutdown();
} else {
hasShutdown = false;
}
sleepQuietly(DETECT_INTERVAL_MS);
}
}
private boolean shouldForceShutdown() {
// 1. 檢測系統時間被竄改
if (detectTimeTampering()) return true;
// 2. 正常時間窗口判斷
Calendar now = Calendar.getInstance();
int hour = now.get(Calendar.HOUR_OF_DAY);
int minute = now.get(Calendar.MINUTE);
if (hour < ALLOW_START_HOUR) return true; // 17點前
if (hour > ALLOW_END_HOUR) return true; // 23點後
if (hour == ALLOW_END_HOUR && minute >= ALLOW_END_MINUTE) return true; // 23:25 後
return false;
}
private boolean detectTimeTampering() {
long now = System.currentTimeMillis();
if (lastCheckMs == 0) {
lastCheckMs = now;
return false;
}
long diff = Math.abs(now - lastCheckMs);
long maxAllowed = DETECT_INTERVAL_MS + 60_000; // 允許 1 分鐘誤差
log("時間差:" + diff + "ms,閾值:" + maxAllowed + "ms");
if (diff > maxAllowed) return true; // 系統時間被修改
lastCheckMs = now;
return false;
}
private void executeShutdown() {
if (hasShutdown) return;
log("觸發強制關機,時間:" + sdf.format(new Date()));
try {
// /s 關機 /t 120 120秒倒計時 /c 提示信息
Runtime.getRuntime().exec("shutdown -s -t 120 -c \"超時使用,2分鐘後自動關機\"");
} catch (IOException e) {
log("關機命令失敗:" + e.getMessage());
}
hasShutdown = true;
}
private void initLog() {
try {
log = new PrintWriter(new FileWriter(LOG_FILE, true), true);
} catch (IOException e) {
log = new PrintWriter(System.out);
}
}
private void log(String msg) { if (log != null) log.println(msg); }
private void sleepQuietly(long ms) {
try { Thread.sleep(ms); } catch (InterruptedException ignored) {}
}
}
}
| 工具 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| WinSW (推薦) | 單一 .exe、XML 配置、支持 .NET/Java、GitHub 熱門 | 需 .NET Runtime | 現代部署、CI/CD 友好 |
| Procrun (Apache Commons Daemon) | 純原生、Tomcat 官方用、成熟穩定 | 配置繁瑣、需安裝 prunsrv.exe | 生產環境標準化 |
| JavaService (文中原方案) | 老牌、輕量 | 停止維護、僅 32 位、JDK 9+ 不兼容 | 維護舊系統 |
WinSW.NET4.exe 重命名為 ShutdownService.exeShutdownService.xml:
AutoShutdown
Auto Shutdown Service
定時關機監控服務
java
-cp "D:/app/shutdown.jar" com.example.TimerShutDownWindows
rotate
Automatic
ShutdownService.exe install
ShutdownService.exe start
net start AutoShutdown # 啟動
net stop AutoShutdown # 停止
sc delete AutoShutdown # 刪除服務
shutdown /s /f /t 0 強制立即關機,防止應用攔截Java + WinSW 實現 Windows 定時關機服務,核心在於:獨立監控線程 + 時間竄改檢測 + 系統級關機命令 + 服務化部署。代碼量小、邏輯清晰,適合學校機房、企業終端管控等場景。