Exploration of exception handling issues in two ways: thread pool excutor submit

Foreword:

  I wonder if you have thought about whether you need to catch internal exceptions in a thread pool executed in excutor or sumbit mode?

For example, I often find the following in my code:

  1. In the thread pool where submit is executed, catch all exceptions, and then the submit method returns true. Finally, the get() method of the thread pool is executed to obtain the number of successful execution results, and the number of successes is returned to the user (think about whether this method is actually useless, there will be no exceptions, and all thread executions will be successful. This is a fake number of successes)

ArrayList<Future<Boolean>> futures = Lists.newArrayList();
for (Target target : targetList) {
    
    
    Future<Boolean> isSuccess = threadPoolExecutor.submit(() -> {
    
    
        // 每一个线程要做的事情
        try {
    
    
             dosomething(target);
        } catch (Exception e) {
    
    
            log.error(e.getMessage(), e);
        }
        //catch 住异常 且返回成功
        return true;
    });
    futures.add(isSuccess);
}
// 使用get去得到submit执行结果
long count = futures.stream().map(s -> {
    
    
    try {
    
    
        return s.get();
    } catch (Exception e) {
    
    
        log.error(e.getMessage(), e);
        return false;
    }
}).filter(s -> s).count();
//模拟返回给用户提示信息 想想这个笔数是否是一个假的笔数呢?是否都是成功的呢?
log.info("当前任务执行完成的笔数{}", count);

  2. In the thread pool where submit is executed, do not deliberately catch the exception, and finally obtain the execution result by executing the get() method.

  If you have ever seen this approach, I recommend you read this article of mine.

Conclusion first

Conclusion one:

  If an exception occurs, the executor will start a new thread for processing (even if the thread pool limit set by threadPoolExecutor is exceeded)


// 1、线程池核心 最大线程数都限制为1个
// 2、线程池执行五次任务,其中一个任务抛出异常去中断该线程
// 3、探究剩余四次任务线程池执行逻辑

// 结论:线程池即使设置为只有1个容量,一个线程因为异常中断后,仍然会再开新的线程,去处理剩余任务

ThreadPoolExecutor pool = new ThreadPoolExecutor( 1, 1,
                                                 30L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

// 五个循环 
IntStream.rangeClosed(1, 5).forEach(i -> pool.execute(() -> {
    
    

    log.info("开始:" + Thread.currentThread().getName());
    if (i == 1) {
    
    
        throw new RuntimeException("异常抛出"); 
    }
    log.info("结束:执行第" + i + "次,"  + Thread.currentThread().getName());
}));

//执行结果 新开了 pool-1-thread-2去执行剩余4次任务
[pool-1-thread-1] INFO com.example.mytest.exceptionTest.futureExcutorException - 开始:pool-1-thread-1
    [pool-1-thread-2] INFO com.example.mytest.exceptionTest.futureExcutorException - 开始:pool-1-thread-2
    [pool-1-thread-2] INFO com.example.mytest.exceptionTest.futureExcutorException - 结束:执行第2次,pool-1-thread-2
    [pool-1-thread-2] INFO com.example.mytest.exceptionTest.futureExcutorException - 开始:pool-1-thread-2
    [pool-1-thread-2] INFO com.example.mytest.exceptionTest.futureExcutorException - 结束:执行第3次,pool-1-thread-2
    [pool-1-thread-2] INFO com.example.mytest.exceptionTest.futureExcutorException - 开始:pool-1-thread-2
    [pool-1-thread-2] INFO com.example.mytest.exceptionTest.futureExcutorException - 结束:执行第4次,pool-1-thread-2
    [pool-1-thread-2] INFO com.example.mytest.exceptionTest.futureExcutorException - 开始:pool-1-thread-2
    [pool-1-thread-2] INFO com.example.mytest.exceptionTest.futureExcutorException - 结束:执行第5次,pool-1-thread-2

Conclusion two:

   If an exception occurs, submit will not report an error (on the surface, the exception has been swallowed)

ThreadPoolExecutor pool = new ThreadPoolExecutor( 1, 1,
                                                 30L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
//提交任务执行
List<Future<Boolean>> tasks = IntStream.rangeClosed(1, 4).mapToObj(i -> pool.submit(() -> {
    
    
    if (i == 2) {
    
    
        throw new RuntimeException("异常抛出");
    }
    return true;
})).collect(Collectors.toList());

// 执行结果 异常不会报错
...

A brief exploration of the reasons

Question 1: At which step does the excutor start a new thread for processing?
Insert image description here

Question 1: Why does submit not report an error (it seems that the exception has been swallowed)?
Insert image description here

Summarize possible problems in the code

   threadPoolExecutor.sumbit (with return value), manually catches the exception and returns true , which is a meaningless identifier of the number of successes, so you cannot use this number of successes as subsequent business execution logic, or as accurate data returned to the user .

Guess you like

Origin blog.csdn.net/qq_44716086/article/details/129203238