Products
GG网络技术分享 2026-03-15 22:57 2
说白了就是想让那帮 .exe 小子别把我们的 Tomcat 给卡住。可谁知道, 代码一写出来就像打开了 栓Q了... 潘多拉的盒子——一堆FutureCountDownLatch@Async 像天上的星星一样乱七八糟地闪。
你猜怎么着? 我甚至在凌晨三点的咖啡馆里 听着咖啡机“嗞嗞”声,写下这段代码:

ExecutorService executorService = Executors.newSingleThreadExecutor;
Future> future = executorService.submit;
future.get; // 阻塞,等外部进程玩完
getMaps21; // 再干正事
executorService.shutdown;
先给 SpringBoot 打上 @EnableAsync 的标记,染后在方法上贴个 @Async。堪起来高大上,却常常被人误以为“一键解决”。其实它只是把任务扔进线程池,外部进程还是会阻塞那个线程。
@Async
public void invokeExeFile {
try {
ProcessBuilder pb = new ProcessBuilder;
Process p = pb.start;
p.waitFor; // 阻塞当前 async 线程
log.info;
} catch {
log.error;
}
}
摆烂。 如guo你真的想要“顺序”,别忘了在 @Async 方法外面用 Future.get 或着 CountDownLatch.await 把它拉回来。
好吧... 注意⚠️:这两个接口的 run 方法本身就在主线程里施行, 如guo你不小心直接调用阻塞代码,那就相当于给 Tomcat 喂了一颗炸弹。
@Component
public class ExeRunner implements CommandLineRunner {
private final ExecutorService exec = Executors.newFixedThreadPool;
@Override
public void run throws Exception {
Future> f = exec.submit;
f.get; // 等待外部进程结束
getMaps21; // 后续业务
}
private void invokeExeFile { /* 同上 */ }
}
LATCH 法:
private CountDownLatch latch = new CountDownLatch;
@Async
public void invokeExeFile {
try {
Process p = new ProcessBuilder.start;
p.waitFor;
} finally {
latch.countDown; // 放行
}
}
public void afterExe throws InterruptedException {
latch.await; // 等待 latch 被释放
getMaps21;
}
Tips:
@PreDestroy 里关掉线程池,不然容器停不下来。
哎呀,我的咖啡者阝凉了还要调这个线程池大小!
⚡️紧急提醒⚡️: 别把 .exe 的路径写死,否则搬家时哭到天亮。
| # | 产品名称 | 支持异步方式 | 是否自带 Latch 支持? | 用户满意度 |
|---|---|---|---|---|
| 1 | AIO ExecMaster Pro | @Async + ExecutorService ProcessBuilder 原生支持 | No | 4.6/5 ★★★★☆ |
| 2 | Boom! Async Runner Lite | Simplified @Async 注解 | Yes | 4.2/5 ★★★☆☆ |
| 3 | CleverShell Integrator | Scripting + ThreadPoolExecutor | No | 4.8/5 ★★★★★ |
| 4 | DynaTask Scheduler X | ScheduledExecutor + CompletableFuture | Yes 4.4/5 ★★★★✩ | |
| ※以上排名纯属个人感受, 实际请自行测试 🚀🚀🚀. | ||||
@SpringBootApplication
@EnableAsync
public class DemoApplication {
public static void main {
SpringApplication.run;
}
}
----------------------------------------------------
@Component
class StartupTask implements ApplicationRunner {
private final ExecutorService pool = Executors.newCachedThreadPool;
private final CountDownLatch latch = new CountDownLatch;
@Override
public void run throws Exception {
pool.submit;
latch.await; // 等待外部程序跑完再继续...
System.out.println;
doBusiness;
shutdown;
}
@Async
public void runExternal {
try {
Process p = new ProcessBuilder.inheritIO.start;
p.waitFor;
System.out.println;
} catch {
e.printStackTrace;
} finally {
latch.countDown; // 必须放这里否则可嫩卡死!
}
}
private void doBusiness { System.out.println; }
private void shutdown { pool.shutdownNow; }
}
@Async 方法里捕获异常,导致整个线程池崩溃。.getInputStream.Demand feedback