如何将ScheduledExecutorService中的异常抛出传播到主线程
问题原因
你原来的写法中子线程抛出的RuntimeException不会影响主线程,是因为
ScheduledExecutorService执行任务时会主动捕获所有任务抛出的未检查异常,存入调度返回的ScheduledFuture对象中,既不会触发线程的未捕获异常处理器,也不会直接向上抛出终止进程。
最优解决方案:通过ScheduledFuture获取异常(完全适配你的测试场景)
scheduleAtFixedRate方法会返回对应任务的ScheduledFuture实例,你只需要主动调用该实例的get()方法,一旦任务抛出异常,get()会立刻抛出封装了原始异常的ExecutionException,直接终止测试流程:
@Test public void executorTest() throws Exception{ ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); // 接收调度返回的Future对象 ScheduledFuture<?> scheduledFuture = executorService.scheduleAtFixedRate(() -> { // 不需要额外catch异常,抛出的异常会自动存入Future Integer.parseInt("error"); }, 0, 100, TimeUnit.MILLISECONDS); try { // get方法会阻塞直到任务异常/被取消 scheduledFuture.get(); } catch (ExecutionException e) { // 抛出原始异常让测试直接失败 throw new RuntimeException("定时任务执行出错", e.getCause()); } finally { executorService.shutdownNow(); } // 任务抛出异常后上面已经终止执行,不会走到这行 System.out.println("should not see this statement"); }
异步感知异常方案(适用于主线程需要同时处理其他逻辑的生产场景)
如果你不需要主线程阻塞等待异常,可以用线程安全的容器存储异常,主线程轮询检查即可:
@Test public void executorTest() throws Exception{ // 线程安全的异常存储容器 AtomicReference<Throwable> exceptionHolder = new AtomicReference<>(); ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); executorService.scheduleAtFixedRate(() -> { try{ Integer.parseInt("error"); }catch (Exception e){ exceptionHolder.set(e); executorService.shutdownNow(); } },0,100, TimeUnit.MILLISECONDS); // 主线程执行其他逻辑的同时定期检查异常 for (int i = 0; i < 10; i++) { if (exceptionHolder.get() != null) { throw new RuntimeException("定时任务执行出错", exceptionHolder.get()); } Thread.sleep(100); } System.out.println("should not see this statement"); }
内容的提问来源于stack exchange,提问作者willy
相关产品推荐
相关产品推荐

