Alice52 / java-ocean

java-tutorial .We intend to explain Java knowledge in this repository.
MIT License
0 stars 0 forks source link

[javase] CompletableFuture #188

Closed Alice52 closed 3 years ago

Alice52 commented 3 years ago

子线程常见的异常处理方式

  1. 手动 try..catch
  2. UncaughtExceptionHandler: 不配置的话也会 log 出异常[java内]
    • 处理异常的顺序:
      • 当前线程有异常处理器
      • 当前线程所属的线程组有异常处理器
      • 全局默认的DefaultUncaughtExceptionHandler
      • 子线程就直接退出: 此时会出现逻辑没有执行, 且没有捕获异常的 log
    • Thread.setUncaughtExceptionHandler 设置当前线程的异常处理器
    • Thread.setDefaultUncaughtExceptionHandler 为整个程序设置默认的异常处理器
  3. Future 的 get/join 可以吧异常直接抛出来

CompletableFuture 中异常问题

  1. join/get 等可以使得子线程的异常被抛出, 进而被 mvc 的全局异常处理器处理
    • 判断结果是否是 exception, 如果是则 throw 出来
  2. @Async 内的子线程异常默认就可以被 mvc 的全局异常处理器处理
  3. 如果是不影响主线程的异步业务, 则需要自己去捕获异常, 否则会出现业务没执行, 也没有任何 log 的诡异
    • 因此需要自己一定要在外层 try..catch
    • code: CompletableFuture async 执行逻辑把次异常捕获了, 转换为 exceptionally了, 此时 CompletableFuture status 是 [Completed exceptionally]
      static final class AsyncRun extends ForkJoinTask<Void> 
          implements Runnable, AsynchronousCompletionTask {
      public void run() {
          ...
              try {
                  f.run();
                  d.completeNull();
              } catch (Throwable ex) {
                  d.completeThrowable(ex);
              }
          ...
      }
      }

Reference

  1. https://www.cnblogs.com/toplist/p/7747225.html
  2. https://www.cnblogs.com/jpfss/p/10272066.html?ivk_sa=1024320u
  3. @Async 注解是怎么实现子线程可以捕获异常的

    • aop 时自己捕获异常并指定异常处理器
    Callable<Object> task = () -> {
        try {
            Object result = invocation.proceed();
            if (result instanceof Future) {
                return ((Future<?>) result).get();
            }
        }
        catch (ExecutionException ex) {
            handleError(ex.getCause(), userDeclaredMethod, invocation.getArguments());
        }
        catch (Throwable ex) {
            handleError(ex, userDeclaredMethod, invocation.getArguments());
        }
        return null;
    };
    
    @Nullable
    protected Object doSubmit(Callable<Object> task, AsyncTaskExecutor executor, Class<?> returnType) {
        if (CompletableFuture.class.isAssignableFrom(returnType)) {
            return CompletableFuture.supplyAsync(() -> {
                try {
                    return task.call();
                }
                catch (Throwable ex) {
                    throw new CompletionException(ex);
                }
            }, executor);
        }
        else if (ListenableFuture.class.isAssignableFrom(returnType)) {
            return ((AsyncListenableTaskExecutor) executor).submitListenable(task);
        }
        else if (Future.class.isAssignableFrom(returnType)) {
            return executor.submit(task);
        }
        else {
            executor.submit(task);
            return null;
        }
    }