如何在Java中检测macOS笔记本电脑的睡眠状态
在Java中检测macOS睡眠与唤醒状态
使用Java 9+的SystemSleepListener(推荐方案)
从Java 9开始,java.awt.Desktop提供了SystemSleepListener接口,可直接监听macOS的睡眠和唤醒事件,这是最优雅且可靠的方式。以下是结合你的ping线程场景的完整实现示例:
import java.awt.Desktop; import java.awt.SystemSleepEvent; import java.awt.SystemSleepListener; public class SleepAwarePingClient { private Thread pingServerThread; public static void main(String[] args) { SleepAwarePingClient client = new SleepAwarePingClient(); client.registerSleepListener(); client.launchPingThread(); } private void registerSleepListener() { Desktop desktop = Desktop.getDesktop(); desktop.addSystemSleepListener(new SystemSleepListener() { @Override public void systemAboutToSleep(SystemSleepEvent event) { // 系统即将进入睡眠,中断ping线程 if (pingServerThread != null && pingServerThread.isAlive()) { pingServerThread.interrupt(); System.out.println("[Sleep Trigger] 中断ping线程"); } } @Override public void systemAwoke(SystemSleepEvent event) { // 系统唤醒,重启ping线程 launchPingThread(); System.out.println("[Wake Trigger] 重启ping线程"); } }); } private void launchPingThread() { pingServerThread = new Thread(() -> { try { while (!Thread.currentThread().isInterrupted()) { // 替换为你的实际ping服务器逻辑 sendPingRequest(); // 模拟ping间隔(5秒) Thread.sleep(5000); } } catch (InterruptedException e) { // 捕获中断信号,优雅退出线程 System.out.println("[Ping Thread] 收到中断信号,停止运行"); Thread.currentThread().interrupt(); // 保留中断状态供上层判断 } }, "pingServer"); pingServerThread.start(); } private void sendPingRequest() { // 你的ping请求实现 System.out.println("[Ping Thread] 发送ping请求到服务器"); } }
关键说明:
- 事件触发时机:
systemAboutToSleep在系统正式睡眠前触发,此时可安全完成线程中断等清理操作;systemAwoke在系统完全唤醒后触发,可重启业务线程。 - 线程中断处理:ping线程通过
Thread.currentThread().isInterrupted()判断是否退出循环,捕获InterruptedException后重置中断状态,避免后续逻辑忽略中断信号。 - 版本与兼容性:该API仅支持Java 9及以上版本,macOS全版本兼容,部分新系统可能需要授予Java程序“辅助功能”权限以确保事件监听正常。
Java 8及以下版本的替代方案
如果项目基于Java 8,无法使用SystemSleepListener,可通过调用macOS原生命令pmset轮询系统状态:
import java.io.BufferedReader; import java.io.InputStreamReader; public class SleepPollingClient { private Thread pingServerThread; public static void main(String[] args) { SleepPollingClient client = new SleepPollingClient(); client.startSleepPoller(); client.launchPingThread(); } private void startSleepPoller() { Thread pollerThread = new Thread(() -> { boolean wasSleeping = false; try { while (!Thread.currentThread().isInterrupted()) { Process process = Runtime.getRuntime().exec("pmset -g assertions"); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; boolean isSleeping = false; while ((line = reader.readLine()) != null) { // 解析pmset输出,判断系统是否允许睡眠 if (line.contains("PreventUserIdleSystemSleep") && line.trim().endsWith("0")) { isSleeping = true; break; } } reader.close(); process.waitFor(); // 状态变化时执行对应操作 if (isSleeping && !wasSleeping) { if (pingServerThread != null && pingServerThread.isAlive()) { pingServerThread.interrupt(); System.out.println("[Poller] 检测到睡眠状态,中断ping线程"); } } else if (!isSleeping && wasSleeping) { launchPingThread(); System.out.println("[Poller] 检测到唤醒状态,重启ping线程"); } wasSleeping = isSleeping; Thread.sleep(10000); // 每10秒轮询一次 } } catch (Exception e) { e.printStackTrace(); } }); pollerThread.start(); } private void launchPingThread() { pingServerThread = new Thread(() -> { try { while (!Thread.currentThread().isInterrupted()) { sendPingRequest(); Thread.sleep(5000); } } catch (InterruptedException e) { System.out.println("[Ping Thread] 收到中断信号,停止运行"); Thread.currentThread().interrupt(); } }, "pingServer"); pingServerThread.start(); } private void sendPingRequest() { System.out.println("[Ping Thread] 发送ping请求到服务器"); } }
注意事项:
- 轮询方式存在延迟,无法像监听器那样实时响应睡眠事件。
pmset的输出格式可能随macOS版本变化,需根据实际系统调整解析逻辑。- 需确保Java程序有权限执行终端命令,部分系统可能需要授予“完全磁盘访问”权限。
内容的提问来源于stack exchange,提问作者Mark Bolduc
相关产品推荐
相关产品推荐

