为什么Vert.x中Verticle的stop方法无法保证被正常调用?
问题根因分析
- 核心原因是
vertx.close()是异步非阻塞API:调用该方法后会立即返回,后续的注销所有Verticle、执行Verticle的stop方法、释放资源等逻辑都在Vertx的异步线程池中执行。当前代码的shutdownHook逻辑中,调用vertx.close()后没有等待异步关闭流程执行完成,就直接结束了shutdownHook线程。JVM在所有注册的shutdownHook执行完成后就会直接终止,此时如果Vertx的关闭流程还没走到MyVerticle的stop方法执行,就会出现对应日志缺失的情况,本质是JVM退出和Vertx关闭流程的竞态条件问题。 - 次要潜在诱因:
vertx.rxDeployVerticle(new MyVerticle()).subscribe()也是异步部署逻辑,如果JVM在部署完成前就触发了关闭流程,此时Verticle还没被注册到Vertx中,自然也不会触发stop方法。
修复方案
可以通过CountDownLatch等待Vertx关闭流程完全执行完成,再结束shutdownHook线程,修复后的示例代码如下:
public class Main { public static void main(String[] args) { Vertx vertx = Vertx.vertx(); // 同步等待Verticle部署完成,避免部署未完成就触发关闭的边界问题 vertx.rxDeployVerticle(new MyVerticle()).blockingSubscribe(); Runtime.getRuntime().addShutdownHook( new Thread(() -> { CountDownLatch closeLatch = new CountDownLatch(1); vertx.close(result -> { System.out.println("Result" + result); closeLatch.countDown(); }); try { // 阻塞等待关闭流程全量执行完成 closeLatch.await(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("Successfully stopped Vertx"); }) ); } } class MyVerticle extends AbstractVerticle { @Override public void start(Future<Void> startFuture) { System.out.println("Successfully started MyVerticle"); startFuture.complete(); } @Override public void stop(Future<Void> stopFuture) { System.out.println("Successfully stopped MyVerticle"); stopFuture.complete(); } }
如果使用RxJava版本的Vertx API,也可以直接调用vertx.rxClose().blockingAwait()更简洁地实现同步等待关闭的效果。
内容的提问来源于stack exchange,提问作者posa bogdan
相关产品推荐
相关产品推荐

