线程池的异常处理方法

131 阅读3分钟

ThreadPoolExecutor

1. try-cahch手动捕获异常

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);
fixedThreadPool.execute(() -> {
    try {
        System.out.println("开始执行业务逻辑");
        throw new RuntimeException();
    } catch (Exception e) {
        //处理出问题的线程
    }
});
TimeUnit.SECONDS.sleep(10);

2. submit方法执行,获得Future对象,在获取返回值接受异常

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);
Future<Object> future = fixedThreadPool.submit(() -> {
    System.out.println("开始执行业务逻辑");
    throw new RuntimeException();
});
try {
    Object o = future.get();
} catch (Exception e) {
    //处理异常
    e.printStackTrace();
}
TimeUnit.SECONDS.sleep(10);

3. 重写线程池的afterExcute方法

下面的代码的task.run();就是执行具体的业务代码的地方,这里如果抛出异常就会执行afterExecute方法,所以就可以重写这个方法,来实现处理异常

final void runWorker(Worker w) {
          //省略前面的代码
          try {
              beforeExecute(wt, task);
              try {
                  task.run();
                  afterExecute(task, null);
              } catch (Throwable ex) {
                  afterExecute(task, ex);
                  throw ex;
              }
          } finally {
              task = null;
              w.completedTasks++;
              w.unlock();
          }
      }
      completedAbruptly = false;
  } finally {
      processWorkerExit(w, completedAbruptly);
  }
}

3.1 先自定义一个线程池

class MyExecutors extends ThreadPoolExecutor {

    public MyExecutors(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }
    //重点就是重写这个方法
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        if (!Objects.isNull(t)) {
            System.out.println("处理异常");
        }
    }
}

3.2 创建自己的线程池

MyExecutors myExecutors = new MyExecutors(1, 1, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
myExecutors.execute(() -> {
    System.out.println("开始执行业务逻辑");
    throw new RuntimeException();
});
TimeUnit.SECONDS.sleep(10);

4 设置线程的UncaughtExceptionHandler方法

Thread对象提供了**setUncaughtExceptionHandler方法用来获取线程中产生的异常**

4.1创建自己的线程工厂类

class MyThreadFactory extends DefaultThreadFactory {

    public MyThreadFactory(String poolName) {
        super(poolName);
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread thread = super.newThread(r);
        //设置要使用的线程的异常处理器
        thread.setUncaughtExceptionHandler((t, e) -> {
            System.out.println("出现错误2");
        });
        return thread;
    }
}

4.2 创建线程池

//这里传入自己定义的线程工厂对象
ExecutorService executorService = Executors.newFixedThreadPool(10, new MyThreadFactory("pool"));
executorService.execute(() -> {
    System.out.println("开始执行业务逻辑");
    throw new RuntimeException();
});
TimeUnit.SECONDS.sleep(10);

ScheduledExecutorService

try-catch:还是可以使用
ScheduledExecutorService:毕竟是用来做延时任务和定时任务的,Future我觉得就不太好了。
UncaughtExceptionHandler:我也不知道为什么不行
afterExcute:不行的,下面细说
  • 虽然说ScheduledExecutorService底层是ThreadPoolExecutor
  • 但是ThreadPoolExecutor是将你传入的lambda表达式是直接执行的run方法执行业务逻辑的,但是ScheduledExecutorService是重新封装的一个RunnableScheduledFuture对象,然后是将任务放入该对象的callable成员变量中,然后重写了run方法,也就是下面这个样子
    public void run() {
        if (!canRunInCurrentRunState(this))
            cancel(false);
        //延时任务
        else if (!isPeriodic())
            super.run();
        //定时任务
        else if (super.runAndReset()) {
            //设置下一次执行的时间
            setNextRunTime();
            //重新入队
            reExecutePeriodic(outerTask);
        }
    }
}
  • 然后在进入具体的执行代码,这里已经捕获了代码然后执行setException方法,所以就可以重写这个方法,实现异常处理
protected boolean runAndReset() {
    //省略前面的代码
    //这里是该线程的状态
    int s = state;
    try {
        Callable<V> c = callable;
        if (c != null && s == NEW) {
            try {
                //这里才是执行具体的业务逻辑
                c.call(); // don't set result
                ran = true;
            } catch (Throwable ex) {
                //然后在这里捕获了异常,所以说afterExecute方法是根本执行不到
                //里面还会改变线程的状态
                setException(ex);
            }
        }
    } finally {
        runner = null;
        s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);

    }
    //一旦出现异常这里就会返回false,也就不会重新入队了
    return ran && s == NEW;
}

自定义FutureTask

class MyFutereTask extends FutureTask {

    public MyFutereTask(Callable callable) {
        super(callable);
    }
    //重点就是重写这个方法
    @Override
    protected void setException(Throwable t) {
        super.setException(t);
        System.out.println("异常处理");
    }
}

创建线程池

ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
MyFutereTask myFutereTask = new MyFutereTask(() -> {
    System.out.println(3);
    throw new RuntimeException();
});
pool.scheduleAtFixedRate(myFutereTask, 0, 1, TimeUnit.SECONDS);