为什么用线程池?解释下线程池参数?

基于:Java 线程池七个参数详解

参考:为什么使用线程池,参数解释、《Java 编程的逻辑》- 马俊昌

为什么用线程池

1、降低资源消耗:提高线程利用率,降低创建和销毁线程的消耗;

2、提高响应速度:任务来了,直接有线程可用可执行,而不用先创建线程,再执行;

3、提高线程的可管理性:线程是稀缺资源,使用线程池可以统一分配调优监控。

线程池参数

Java 并发包中线程池的实现类是 ThreadPoolExecutor,ThreadPoolExecutor 有一些重要的参数:

public class ThreadPoolExecutor extends AbstractExecutorService {
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
// ...
}
}

1、int corePoolSize代表核心线程数。线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会被销毁,除非设置了 allowCoreThreadTimeOut。这里的最小线程数量即是 corePoolSize。任务提交到线程池后,首先会检查当前线程数是否达到了 corePoolSize,如果没有达到的话,则会创建一个新线程来处理这个任务。

2、int maximumPoolSize代表的是最大线程数。当前线程数达到 corePoolSize 后,如果继续有任务被提交到线程池,会将任务缓存到工作队列(后面会介绍)中。如果队列也已满,则会去创建一个新线程来出来这个处理。线程池不会无限制的去创建新线程,它会有一个最大线程数量的限制,这个数量即由 maximumPoolSize 指定。

3、long keepAliveTime表示空闲存活时间。一个线程如果处于空闲状态,并且当前的线程数量大于 corePoolSize,那么在指定时间后,这个空闲线程会被销毁,这里的指定时间由 keepAliveTime 来设定。

4、TimeUnit unit表示 keepAliveTime 的时间单位。

5、BlockingQueue<Runnable> workQueue表示工作队列,用来存放待执行的任务。有以下几种常见的工作队列:

  1. ArrayBlockingQueue

    基于数组的有界阻塞队列,按 FIFO 排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。当线程池中线程数量达到 corePoolSize 后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到 maxPoolSize,则会执行拒绝策略。

  2. LinkedBlockingQueue

    基于链表的“有界”阻塞队列(默认最大容量为 Integer.MAX),按照 FIFO 排序。由于该队列最大容量为 Integer.MAX 时近似无界性,当线程池中线程数量达到 corePoolSize 后,再有新任务进来,会一直存入该队列,而基本不会去创建新线程直到 maxPoolSize(很难达到 Integer.MAX 这个数),因此使用该工作队列时,参数 maxPoolSize 其实是不起作用的。

  3. SynchronousQueue

    一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到 maxPoolSize,则执行拒绝策略。

  4. PriorityBlockingQueue

    具有优先级的无界阻塞队列,优先级通过参数 Comparator 实现。

6、ThreadFactory threadFactory线程工厂,用来生产线程执行任务。我们可以选择使用默认的创建工厂,产生的线程都在同一个组内,拥有相同的优先级,且都不是守护线程。当然我们也可以选择自定义线程工厂,用来设定线程名、是否为 daemon 线程等等。

7、RejectedExecutionHandler handler任务拒绝策略。当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题的,JDK 中提供了 4 中拒绝策略:

  1. CallerRunsPolicy

    该策略下,在调用者线程中直接执行被拒绝任务的 run 方法,除非线程池已经 shutdown,则直接抛弃任务。

    public static class CallerRunsPolicy implements RejectedExecutionHandler {
    /**
    * Creates a {@code CallerRunsPolicy}.
    */
    public CallerRunsPolicy() { }
    /**
    * Executes task r in the caller's thread, unless the executor
    * has been shut down, in which case the task is discarded.
    *
    * @param r the runnable task requested to be executed
    * @param e the executor attempting to execute this task
    */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    if (!e.isShutdown()) {
    r.run();
    }
    }
    }
  2. AbortPolicy

    该策略下,直接丢弃任务,并抛出 RejectedExecutionException 异常。

    public static class AbortPolicy implements RejectedExecutionHandler {
    /**
    * Creates an {@code AbortPolicy}.
    */
    public AbortPolicy() { }
    /**
    * Always throws RejectedExecutionException.
    *
    * @param r the runnable task requested to be executed
    * @param e the executor attempting to execute this task
    * @throws RejectedExecutionException always
    */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    throw new RejectedExecutionException("Task " + r.toString() +
    " rejected from " +
    e.toString());
    }
    }
  3. DiscardPolicy

    该策略下,直接丢弃任务,什么都不做。

    public static class DiscardPolicy implements RejectedExecutionHandler {
    /**
    * Creates a {@code DiscardPolicy}.
    */
    public DiscardPolicy() { }
    /**
    * Does nothing, which has the effect of discarding task r.
    *
    * @param r the runnable task requested to be executed
    * @param e the executor attempting to execute this task
    */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    }
    }
  4. DiscardOldestPolicy

    该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列。

    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
    /**
    * Creates a {@code DiscardOldestPolicy} for the given executor.
    */
    public DiscardOldestPolicy() { }
    /**
    * Obtains and ignores the next task that the executor
    * would otherwise execute, if one is immediately available,
    * and then retries execution of task r, unless the executor
    * is shut down, in which case task r is instead discarded.
    *
    * @param r the runnable task requested to be executed
    * @param e the executor attempting to execute this task
    */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    if (!e.isShutdown()) {
    e.getQueue().poll();
    e.execute(r);
    }
    }
    }
posted @   Higurashi-kagome  阅读(58)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
点击右上角即可分享
微信分享提示