跳至主要內容

java线程池队列问题

zheng大约 4 分钟java基础线程

问题:
Java线程池,5核心、10最大、20队列,第6个任务来了是什么状态?第26个任务来了是什么状态?队列满了以后执行队列的任务是从队列头 or 队尾取?
核心线程和非核心线程执行结束后,谁先执行队列里的任务?

在Java中,线程池的配置和行为由ThreadPoolExecutor类控制。根据你提供的参数,假设你创建了一个具有以下配置的线程池:

  • 核心线程数(corePoolSize):5
  • 最大线程数(maximumPoolSize):10
  • 任务队列容量(queue capacity):20

1. 第6个任务来了是什么状态?

当第6个任务提交时,线程池的行为如下:

  • 前5个任务:这5个任务会被立即分配给核心线程(因为核心线程数为5),并且这些线程会开始执行这些任务。
  • 第6个任务:由于核心线程数已经用完,第6个任务不会立即启动新的线程来执行它。相反,它会被放入任务队列中等待执行。

因此,第6个任务的状态是“已进入任务队列,等待执行”

2. 第26个任务来了是什么状态?

当第26个任务提交时,线程池的行为如下:

  • 前5个任务:由核心线程执行。
  • 第6到第25个任务:这20个任务会被放入任务队列中,因为队列容量为20。
  • 第26个任务:此时,任务队列已经满了(20个任务已经在队列中),并且所有核心线程都在忙碌。根据线程池的配置,接下来会发生以下情况:
    • 如果当前活动线程数小于最大线程数(10),线程池会创建一个新的非核心线程来执行第26个任务。
    • 如果当前活动线程数已经达到最大线程数(10),并且任务队列也已满,那么线程池将拒绝这个任务,并抛出RejectedExecutionException,除非你指定了一个自定义的拒绝策略。

因此,第26个任务的状态取决于当前活动线程数

  • 如果活动线程数小于10,第26个任务会被分配给新创建的非核心线程执行。
  • 如果活动线程数已经达到10且队列已满,第26个任务将被拒绝(默认情况下抛出RejectedExecutionException)。

3. 队列满了以后执行队列的任务是从队列头还是队尾取?

Java的ThreadPoolExecutor默认使用的是FIFO(先进先出)队列,例如LinkedBlockingQueue。这意味着任务是按照它们进入队列的顺序被执行,即从队列头取任务

如果你使用的是其他类型的队列(如PriorityBlockingQueueSynchronousQueue),则行为可能会不同。但根据你提供的信息,默认情况下,任务是从队列头取出的。

4. 核心线程和非核心线程执行结束后,谁先执行队列里的任务?

ThreadPoolExecutor中,核心线程和非核心线程并没有优先级的区别。当有任务需要执行时,线程池会根据可用的线程来分配任务,而不会区分核心线程和非核心线程。

具体来说:

  • 当某个任务完成时,无论是核心线程还是非核心线程,该线程都会返回到线程池的空闲线程集合中。
  • 然后,线程池会从任务队列中取出下一个任务,并将其分配给第一个可用的空闲线程(无论是核心线程还是非核心线程)。

因此,没有固定的优先级,任何可用的线程都可以执行队列中的任务。

5. 总结

  • 第6个任务:进入任务队列,等待执行。
  • 第26个任务:如果活动线程数小于10,创建新的非核心线程执行;如果活动线程数已达10且队列已满,任务将被拒绝。
  • 任务队列:默认情况下,任务是从队列头(FIFO)取出。
  • 核心线程和非核心线程:没有优先级区别,任何可用的线程都可以执行队列中的任务。

6. 额外说明:线程池的拒绝策略

如果你希望自定义任务被拒绝时的行为,可以通过设置RejectedExecutionHandler来实现。常见的拒绝策略包括:

  • CallerRunsPolicy:由调用线程(提交任务的线程)执行被拒绝的任务。
  • AbortPolicy:抛出RejectedExecutionException(默认行为)。
  • DiscardPolicy:直接丢弃被拒绝的任务,不抛出异常。
  • DiscardOldestPolicy:丢弃队列中最老的任务,然后尝试重新提交被拒绝的任务。

你可以通过ThreadPoolExecutor的构造函数或setRejectedExecutionHandler方法来设置自定义的拒绝策略。

上次编辑于:
贡献者: 郑天祺