ExecutorService.invokeAll() 线程池批量执行任务,一定条件下会死锁

根据阿里开发规范,不推荐使用Executors直接创建线程池,应使用构造方法并明确目的。线程池执行逻辑涉及队列满时的拒绝策略,如设置无限大小队列则失去意义。在特定情况下,DiscardPolicy和DiscardOldestPolicy策略可能会导致线程池死锁,这是一个重要的并发问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程池的创建

ThreadPoolExecutor 的构造方法

	 public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)
字段含义
corePoolSize核心线程池大小
maximumPoolSize线程池最大大小
keepAliveTime超过核心数量时,多长时间开始回收空闲线程
unit时间单位
workQueue任务队列
threadFactory
handler拒绝策略

阿里开发规范中建议不要使用例如 Executors.newFixedThreadPool(10) 这种方式创建线程池,建议直接用构造方法创建线程池,明确创建线程池的目的

线程池的执行逻辑是,

1.有任务来时,如果没有线程处理,就创建线程直到corePoolSize数量为止
2.再有任务过来,则放入队列中
3.当队列满了则创建线程,直到maximumPoolSize,但这一部分线程在keepAliveTime的空闲时间后会回收,这是线程池内会一直保持这corePoolSize数量的线程

所以就有,

如果corePoolSize == maximumPoolSize 则线程池在队列满了不会在创建线程,且`keepAliveTime`就失去了意义	
如果workQueue 是一个无限大小的队列,例如linkedqueue则永远填不满,直到oom也不会再创建新的线程,所以corePoolSize初始化太小,并且用linkedqueue的情况会导致没有足够的线程处理任务
所以建议根据实际情况调节corePoolSize,maximumPoolSize,workQueue的大小

拒绝策略(队列满了会如何处理,所以使用无限大小的队列这个参数就没有意义了)

DiscardPolicy (多余的任务,直接丢弃。相当于丢弃丢列尾部的任务)
AbortPolicy (报错)
DiscardOldestPolicy(丢弃最老的任务,相当于丢弃队列头部的任务)
还有其他两种,具体请看 RejectedExecutionHandler接口的实现类,逻辑很简单。

批量执行

ExecutorService.invokeAll()方法接收一个list<Callable>,当全部任务都执行完成后返回List<Future<T>> futures
并且这种方式是能保证请求和返回值的一一对应关系,顺序是一致的

批量执行时有种情况

当批量执行的任务数量大于线程池数量+队列数量,这时根据拒绝策略会有不同情况讨论

AbortPolicy 这时会将报错后的任务以及前面没执行完的任务取消

DiscardPolicy,DiscardOldestPolicy 这两种情况会导致线程池锁住 ( 重要 )

**因为invokeAll方法上会调用future.get方法,且是堵塞的,如果任务被丢弃了,则会永远堵塞在这里**

'''
  if (tasks == null)
        throw new NullPointerException();
    List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
    boolean done = false;
    try {
        for (Callable<T> t : tasks) {
            RunnableFuture<T> f = newTaskFor(t);
            futures.add(f);
            execute(f);
        }
        for (Future<T> f : futures) {
            if (!f.isDone()) {
                try {
                    f.get();             <-------- ,如果任务被丢弃,这里会堵住
                } catch (CancellationException ignore) {
                } catch (ExecutionException ignore) {
                }
            }
        }
        done = true;
        return futures;
    } finally {
        if (!done)
            for (Future<T> f : futures)
                f.cancel(true);
    }	


'''
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值