Java Vertx定时任务场景下如何正确返回预期JsonObject结果
问题根因
你的代码核心问题是定时任务的执行是异步操作:调用time.schedule()后只是提交了调度任务,不会等待任务执行完成,你立刻读取ScheduledTask里的JsonObject时,run()方法还没被触发,拿到的永远是初始化的空对象。
同时你现在的写法每次接口请求都会新建一个周期性执行的Timer实例,没有销毁逻辑,会造成严重的内存泄漏。
解决方案
根据你的业务需求分两种场景调整:
场景1:仅需要单次执行业务逻辑,执行完成后返回结果
不需要自定义TimerTask,直接使用Vert.x原生的定时API即可,完全适配Vert.x的线程模型:
public void getNum(RoutingContext context){ // 延迟0ms执行,即立即异步执行业务逻辑 vertx.setTimer(0, timerId -> { JsonObject jo = new JsonObject(); try { // 此处放入你原ScheduledTask中run方法的业务逻辑,获取split数组 jo.put("file", split[0]); jo.put("recogTime", split[1]); jo.put("number", split[2]); log.info(jo.encodePrettily()); // 逻辑执行完成后再返回响应 context.response() .putHeader("content-type", "application/json") .setStatusCode(200) .end(jo.encodePrettily()); } catch (Exception e){ e.printStackTrace(); log.info("Error.Running.1stCMD"); context.response().setStatusCode(500).end("服务执行异常"); } }); }
场景2:确实需要周期性执行业务逻辑,接口返回最近一次执行的结果
不要在接口逻辑里创建定时任务,全局仅初始化一次定时任务即可:
- 在Verticle启动时初始化定时任务
// 作为Verticle的成员变量存储最新的执行结果 private JsonObject latestResult = new JsonObject(); @Override public void start() throws Exception { // 启动周期为500ms的定时任务,全局仅启动一次 vertx.setPeriodic(500, timerId -> { try { // 此处放入你的业务逻辑,获取split数组 JsonObject jo = new JsonObject(); jo.put("file", split[0]); jo.put("recogTime", split[1]); jo.put("number", split[2]); log.info(jo.encodePrettily()); // 更新最新结果 latestResult = jo; } catch (Exception e){ e.printStackTrace(); log.info("Error.Running.1stCMD"); } }); // 注册路由 router.get("/getNum").handler(this::getNum); }
- 接口直接读取最新结果返回
public void getNum(RoutingContext context){ context.response() .putHeader("content-type", "application/json") .setStatusCode(200) .end(latestResult.encodePrettily()); }
注意事项
- 如果有多个线程读写结果对象,需要加同步锁控制,避免返回半初始化的数据
- 禁止在请求处理逻辑中重复创建周期性任务,会导致实例不断堆积最终内存溢出
内容的提问来源于stack exchange,提问作者user17085185
相关产品推荐
相关产品推荐

