掘金 后端 ( ) • 2024-06-21 17:18

1 线程执行程序,发生异常,通过try{}catch 捕抓异常

 try{
    }catch(Excecption e){
        //异常处理逻辑
     }

2 线程池中线程发生异常,如何处理

提出问题:

从以下三个维度来分析下线程异常后执行情况

  1. 线程池是否抛出异常
  2. 线程是否删除
  3. 异常线程是否影响线程池中其他线程

得到结论:

不同执行方式处理异常不一致,线程池执行线程两种方式

  • pool.execute(runnable):线程池抛出异常,线程删除,不影响
  • pool.sumbit(runnable):线程池不抛出异常,线程不删除,不影响

代码验证:

execute


package com.hmh.thread;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
* @author: hmh
* @date :2024/6/18 10:12
*/
public class ThreadPoolExceptionTest {

   static ThreadFactory threadFactory = new ThreadFactory() {
       @Override
       public Thread newThread(Runnable r) {
           Thread thread = new Thread(r);
           thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
               @Override
               public void uncaughtException(Thread t, Throwable e) {
                   System.out.println(Thread.currentThread().getName()+" 抛出异常:" + e);
               }
           });
           return thread;
       }
   };

   private static ThreadPoolExecutor pool =
          new ThreadPoolExecutor(
                  4,
                  8,
                  2,
                  TimeUnit.SECONDS,
                  new ArrayBlockingQueue<>(100),
                  threadFactory,
                  new ThreadPoolExecutor.CallerRunsPolicy()
          );


   private static void printPool() {
       String format = String.format("coreSize:%s,maxSize:%s,avalableSize:%s", pool.getCorePoolSize(),
               pool.getMaximumPoolSize(),
               pool.getActiveCount());
       System.out.println(format);
   }

   public static void execTask(String name) {

       System.out.println(Thread.currentThread().getName()+" =======run");
       if(name.equals("execute-exception")) {
           System.out.println(1/0);
       }
   }
   public static void main(String... args) throws InterruptedException {

   pool.execute(()->execTask("execute-exception"));
   TimeUnit.MILLISECONDS.sleep(10);
   pool.execute(()->execTask("execute"));
   pool.execute(()->execTask("execute"));
   pool.execute(()->execTask("execute"));

   printPool();
   pool.shutdown();
   }
}
  
执行结果:
线程池中线程异常,execute抛出异常;删除异常线程并新增一个空线程,且空线程名称是异常线程+1,后续线程池中没有异常线程;线程1,2互不影响

image.png

源码分析:

execute ThreadPoolExecutor.execute() ----> addWorker() ----->ThreadPoolExecutor.Worker().run() ----->ThreadPoolExecutor.runWorker()

runWorker()执行异常后,抛出异常,

image.png

processWorkerExit() 线程池中不会存在异常线程的线程

image.png

addWorker(null,false):空线程名称是在异常线程后,名称+1

new Worker(firstTask);

image.png

submit


    pool.submit(()->execTask("execute"));
    pool.submit(()->execTask("execute"));
    Future<?> submit = pool.submit(() -> execTask("execute-exception"));
    try {
        submit.get();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
    pool.submit(()->execTask("execute"));
    printPool();

    pool.shutdown();

执行结果:

线程池中线程异常,sumbit不抛出异常,只有get结果时抛出异常;删除异常线程并新增一个空线程,且空线程名称是异常线程+1,后续线程池中没有异常线程;线程1,2互不影响

image.png

源码分析:

ThreadPoolExecutor.submit() ----> excute(furetask) ----> addWorker() ----> FutrueTask.run()

image.png ----> setException() 这个异常会不会在往外抛出,导致执行时不会报错

image.png 在执行完成后,get处理结果,抛出异常 ----> FutrueTask.get() ----> FutrueTask.report()

image.png