如何让Picocli等待Javalin长运行线程,避免程序立即退出?
解决Picocli启动Javalin后程序立即退出的问题
问题场景
我想要构建一个简单的Javalin API,通过Picocli命令行参数配置HTTP端口,代码如下:
public class Main implements Runnable { @CommandLine.Option(names = {"-p", "--port"}) int httpPort = 9080; public static void main(String... args) { int exitCode = new CommandLine(new Main()).execute(args); System.exit(exitCode); } @Override public void run() { Javalin.create() .get("/some/endpoint", new EndpointHandler()) .start("0.0.0.0", httpPort); } }
遇到的问题:Picocli启动Javalin线程后,程序会立即返回并退出,无法保持服务器运行。
解决方案
方案1:改用Javalin的阻塞启动方法
Javalin的start()是异步非阻塞的,启动后会直接返回,导致run()方法执行完毕,Picocli流程结束进而触发程序退出。换成startBlocking()方法即可让当前线程阻塞,直到服务器停止:
@Override public void run() { Javalin.create() .get("/some/endpoint", new EndpointHandler()) .startBlocking("0.0.0.0", httpPort); }
方案2:手动阻塞主线程
如果需要保留异步启动(比如启动后要执行其他逻辑),可以在启动服务器后让线程等待服务器关闭。比如通过服务器线程的join()方法:
@Override public void run() { Javalin app = Javalin.create() .get("/some/endpoint", new EndpointHandler()) .start("0.0.0.0", httpPort); try { // 阻塞当前线程,直到服务器线程结束 app.thread().join(); } catch (InterruptedException e) { // 恢复中断状态 Thread.currentThread().interrupt(); } }
或者用CountDownLatch监听服务器停止事件:
import java.util.concurrent.CountDownLatch; @Override public void run() { CountDownLatch shutdownLatch = new CountDownLatch(1); Javalin.create() .get("/some/endpoint", new EndpointHandler()) .start("0.0.0.0", httpPort) .events(event -> { // 服务器停止时释放 latch event.serverStopped(shutdownLatch::countDown); }); try { // 等待直到 latch 被释放 shutdownLatch.await(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }
核心原因
Picocli执行完run()方法后会返回并触发System.exit(exitCode),而Javalin的start()是异步启动服务器,不会阻塞当前线程,所以run()方法很快执行完毕,导致整个程序退出。使用阻塞启动方法或手动阻塞线程,就能让程序保持运行直到服务器停止。
内容的提问来源于stack exchange,提问作者Thomas
相关产品推荐
相关产品推荐

