无法获取Callable类返回值,始终抛出TimeoutException求助
问题解决:连接检查器TimeoutException及Callable返回值获取问题
核心问题分析
- Ping命令错误:Linux/OSX分支中使用了带
https//的URL,ping是ICMP协议工具,不支持HTTP协议前缀,会导致命令执行失败且进程挂起。 - Process流阻塞:未读取子进程的标准输出/错误输出,缓冲区满时会导致进程无法结束,
waitFor()一直阻塞,Callable无法返回结果。 - Future结果处理错误:原代码未正确接收Callable的返回值,无论
get()是否成功都直接设connected=true,逻辑错误。
修正方案
1. 修复ConnectionChecker类
修正ping命令,添加流处理避免阻塞:
public class ConnectionChecker implements Callable<Boolean> { @Override public Boolean call() throws Exception { String cmd; // 使用IP地址避免域名解析额外耗时,也可替换为可靠域名如www.baidu.com String target = "1.1.1.1"; if (System.getProperty("os.name").startsWith("Windows")) { cmd = "ping -n 1 " + target; } else { cmd = "ping -c 1 " + target; } Process myProcess = Runtime.getRuntime().exec(cmd); // 异步读取输出流,避免缓冲区满阻塞进程 new Thread(() -> { try (InputStream in = myProcess.getInputStream()) { in.readAllBytes(); } catch (IOException e) { e.printStackTrace(); } }).start(); // 异步读取错误流 new Thread(() -> { try (InputStream err = myProcess.getErrorStream()) { err.readAllBytes(); } catch (IOException e) { e.printStackTrace(); } }).start(); // 等待进程结束并获取退出码 int exitCode = myProcess.waitFor(); boolean isConnected = exitCode == 0; System.out.println(isConnected); return isConnected; } }
2. 修复Updater类的Future结果处理
正确接收Callable返回值,完善异常处理:
public class Updater implements Runnable { private final JLabel label; private final ExecutorService executor; public Updater(JLabel label, ExecutorService executor) { this.label = label; this.executor = executor; } public void run() { boolean connected = false; Callable<Boolean> callable = new ConnectionChecker(); Future<Boolean> connHandle = executor.submit(callable); try { // 正确获取Callable的返回结果 connected = connHandle.get(5, TimeUnit.SECONDS); } catch (TimeoutException ex) { connected = false; ex.printStackTrace(); // 超时后取消未完成的任务 connHandle.cancel(true); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); connected = false; } catch (CancellationException | ExecutionException ex) { connected = false; ex.printStackTrace(); } final boolean result = connected; SwingUtilities.invokeLater(() -> { label.setText(result ? "online" : "offline"); }); } }
额外优化建议
- 可以将目标地址(1.1.1.1)作为参数传入ConnectionChecker,增强灵活性。
- 对于Swing界面更新,可使用
SwingWorker替代手动线程调度,更符合Swing线程模型规范。
内容的提问来源于stack exchange,提问作者Jessica
相关产品推荐
相关产品推荐

