线程池excutor submit 两种方式 对于异常的处理问题的探究

前言:

  不知大家在对待excutor or sumbit方式执行的线程池,内部出现异常是否要catch住这个问题有没有思考?

例如,我常在代码中发现以下处理方式:

  1、在submit执行的线程池中,catch住所有异常,然后submit方法返回true。最后通过执行线程池的get()方法来获取执行结果成功次数,并且把这个成功次数返回给用户(想想是否这种方法其实是没有用的,不会有异常,所有的线程执行都会成功,这个是个假的成功次数)

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、在submit执行的线程池中,不刻意catch住异常,最后通过执行get()方法来获取执行结果

  如果你也曾经看到过这样的处理方式,我推荐你看下我的这篇文章。

结论先行

结论一:

  发生异常,excutor会开启新线程处理(即使超过了threadPoolExecutor设置的线程池上限)


// 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

结论二:

   发生异常,submit不会报错(表面看来,异常被吞掉了)

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());

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

原因简单探究

问题一:excutor是在哪一步去开启新线程处理?
在这里插入图片描述

问题一:submit不会报错(表面上看起来异常被吞掉了)的原因是为啥?
在这里插入图片描述

总结代码中可能存在的问题

   threadPoolExecutor.sumbit (带返回值),手动catch住异常且返回了ture,是一个没有意义的成功次数标识,所以你不能用这个成功次数去作为之后的业务执行逻辑,或者作为返回给用户的精准数据。

猜你喜欢

转载自blog.csdn.net/qq_44716086/article/details/129203238