如何实现超时后自动执行代码,满足RS232传感器采集的看门狗需求
实现方案推荐
选型优先级
- 首选:
ScheduledExecutorService(通用场景,并发安全,容错性高) - 次选:如果是Swing桌面程序,可选
javax.swing.Timer(自动将任务回调放到UI事件调度线程,不用手动处理线程安全) - 不推荐:自行实现Thread/Runnable、
java.util.Timer、额外引入看门狗框架
选型优劣说明
- 自行实现Thread/Runnable:需要手动处理中断、任务重置、线程同步,容易出现死锁、漏重置等并发问题,重复造轮子没有必要
java.util.Timer:单线程调度,多任务会互相阻塞,一旦某个任务抛出未捕获异常会直接导致整个定时器失效,容错性极差- 自定义看门狗框架:本质就是超时重置的定时器逻辑,用JDK自带的调度工具即可实现,无需额外封装增加复杂度
核心实现逻辑
你需要的看门狗逻辑非常简单,只需要每次收到串口数据时取消旧的超时任务,提交新的超时任务即可:
- 初始化调度器和超时任务引用
- 每次收到新的传感器数据时重置定时器
- 超时后执行停止采集的逻辑
代码示例(Java通用版)
import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; public class SensorCollector { // 2秒超时 private static final long TIMEOUT_MS = 2000; // 单线程调度器,足够处理超时任务 private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); // 保存待执行的超时任务,用于取消 private ScheduledFuture<?> timeoutTask; // 你原来的串口数据收到的回调方法 public void onSensorDataReceived(String data) { // 1. 收到新数据,先重置定时器:取消旧的超时任务 resetTimeoutTimer(); // 2. 你原来的处理数据、更新UI的逻辑 // processData(data); } private void resetTimeoutTimer() { // 取消上一个未执行的超时任务,mayInterruptIfRunning设为false就行,因为任务还没执行 if (timeoutTask != null && !timeoutTask.isDone()) { timeoutTask.cancel(false); } // 提交新的超时任务,2秒后执行 timeoutTask = scheduler.schedule(this::onCollectTimeout, TIMEOUT_MS, TimeUnit.MILLISECONDS); } // 超时触发的逻辑,就是你原来按钮点击的注销监听器、停止采集的逻辑 private void onCollectTimeout() { // 停止采集的操作:将控制器从消息监听器列表注销、关闭记录等 // unregisterListener(); // stopRecord(); System.out.println("连续2秒无数据,自动停止采集"); } // 程序退出/手动停止采集时记得关闭调度器释放资源 public void shutdown() { scheduler.shutdownNow(); } }
注意事项
- 如果是Swing/JavaFX桌面程序,
onCollectTimeout中涉及UI更新的操作,需要放到对应平台的UI线程执行:- Swing:用
SwingUtilities.invokeLater()包裹UI操作 - JavaFX:用
Platform.runLater()包裹UI操作
- Swing:用
- 程序主动停止采集时,记得调用
shutdown()方法关闭调度器,避免线程泄漏 - 如果不需要重复使用定时器,停止采集后也可以主动取消当前的
timeoutTask,避免误触发
内容的提问来源于stack exchange,提问作者froggy
相关产品推荐
相关产品推荐

