Java线程池七个参数详解:核心线程数、最大线程数、空闲线程存活时间、时间单位、工作队列、线程工厂、拒绝策略

以下是对 Java 线程池中七个参数的详细解释:

  1. 核心线程数(corePoolSize)

    • 这是线程池中保持活跃的最小线程数量。即使这些线程处于空闲状态,它们也不会被销毁,除非允许核心线程超时。
    • 例如,如果设置为 5 ,那么线程池启动时会立即创建 5 个线程准备执行任务。
  2. 最大线程数(maximumPoolSize)

    • 线程池中允许的最大线程数量。当任务队列已满且核心线程都在忙碌时,会创建新线程,直到达到这个数量。
    • 比如,最大线程数设为 10 ,核心线程数为 5 ,当任务积压且 5 个核心线程都忙时,会创建新线程,最多到 10 个。
  3. 空闲线程存活时间(keepAliveTime)

    • 当线程数量超过核心线程数时,多余的空闲线程在等待新任务的最长存活时间。
    • 假设设置为 30 秒,如果空闲线程在 30 秒内没有接收到新任务,就可能被销毁。
  4. 时间单位(unit)

    • 用于指定空闲线程存活时间的时间单位,如 TimeUnit.SECONDS(秒)、TimeUnit.MILLISECONDS(毫秒)等。
  5. 工作队列(workQueue)

    • 用于存储等待执行的任务。常见的有 ArrayBlockingQueue(有界队列)、LinkedBlockingQueue(无界队列)等。
    • 例如,使用有界队列可以限制等待任务的数量,防止任务过度积压。

    选择线程的工作队列时,需要考虑以下几个因素:

    1. 任务数量和预期的并发程度
      • 如果任务数量较少且并发程度较低,使用一个无界队列(如 LinkedBlockingQueue)可能是合适的,因为它可以容纳任意数量的任务,不会因为队列满而导致任务提交失败。
      • 然而,如果任务数量可能会大量堆积或者并发程度较高,有界队列(如 ArrayBlockingQueue)可以更好地控制资源使用,避免内存过度消耗。
    2. 内存资源
      • 无界队列可能会导致大量任务堆积在内存中,如果系统内存有限,使用有界队列可以防止内存溢出。
    3. 任务处理的优先级
      • 某些场景下可能需要根据任务的优先级进行处理。例如,PriorityBlockingQueue 可以按照任务的优先级顺序执行任务。
    4. 任务的特性
      • 如果任务之间有依赖关系或者需要按照特定顺序执行,可能需要使用更复杂的数据结构来实现工作队列。
    5. 系统的稳定性和可靠性
      • 选择一个合适的队列类型可以避免因为任务堆积导致系统不稳定或者崩溃。

    常见的工作队列选择示例:

    1. 如果任务量较小且对内存使用不太敏感,希望任务提交永远不会失败,可以选择 LinkedBlockingQueue
    2. 如果需要控制内存使用,防止任务过度堆积导致内存问题,ArrayBlockingQueue 并设置合适的容量是一个较好的选择。
    3. 如果任务有优先级区分,PriorityBlockingQueue 能够满足按照优先级处理任务的需求。
  6. 线程工厂(threadFactory)

    • 用于创建新线程,可以自定义线程的属性,如线程名称、优先级、守护线程属性等。
    • 比如,可以创建一个线程工厂,为线程设置有意义的名称,方便调试和监控。
  7. 拒绝策略(handler)

    • 当线程池无法处理新任务(工作队列已满且线程数达到最大)时采取的策略。
    • 常见的拒绝策略有:
      • AbortPolicy:默认策略,直接抛出 RejectedExecutionException 异常。
      • CallerRunsPolicy:让提交任务的线程自己执行任务。
      • DiscardOldestPolicy:丢弃工作队列中最旧的未处理任务,然后尝试重新提交新任务。
      • DiscardPolicy:直接丢弃新任务,不做任何处理。

以下是一个配置线程池的示例代码:

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

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 创建线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                5, // 核心线程数
                10, // 最大线程数
                30, TimeUnit.SECONDS, // 空闲线程存活时间和时间单位
                new ArrayBlockingQueue<>(100), // 工作队列,容量为 100
                r -> {
                    Thread thread = new Thread(r);
                    thread.setName("自定义线程名称 - " + thread.getId());
                    return thread;
                }, // 线程工厂
                new ThreadPoolExecutor.AbortPolicy()); // 拒绝策略

        // 提交任务
        for (int i = 0; i < 200; i++) {
            executor.execute(() -> {
                System.out.println(Thread.currentThread().getName() + " 正在执行任务");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        // 关闭线程池
        executor.shutdown();
    }
}

在上述示例中,创建了一个线程池,核心线程数为 5 ,最大线程数为 10 ,空闲线程存活时间为 30 秒,工作队列容量为 100 ,自定义了线程工厂,并使用了默认的拒绝策略 AbortPolicy 。然后向线程池提交了 200 个任务。

你可能感兴趣的:(Java面试,java,开发语言)