SpringBoot 线程池的使用

SpringBoot 使用线程池

/**
 *  线程池的配置和初始化
 */
@Data
@ConfigurationProperties("executor")
@Configuration
public class ThreadExecutorPool {
    private Integer corePoolSize;
    private Integer maxPoolSize;
    private Integer queueCapacity;
    private Integer keepAliveSeconds;
    private String threadNamePrefix;

    @Bean("taskAsyncPool")
    public ThreadPoolTaskExecutor taskAsyncPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);executor.setKeepAliveSeconds(keepAliveSeconds);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setThreadNamePrefix(getThreadNamePrefix());
        executor.initialize();
        return executor;
    }
}

配置文件

executor:
    corePoolSize: 5
    maxPoolSize: 10
    queueCapacity: 20
    keepAliveSeconds: 60
    threadNamePrefix: XCExecutor-
  • 在SpringBoot启动类上增加@EnableAsync注解
  • 然后再需要多线程执行的方法上增加@Async(value = "taskAsyncPool")注解即可

线程池

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后再创建线程后自动启动这些任务。

为什么使用线程池

一般使用线程的方式有两种:一种是继承Thread类,一种是实现Runnable的接口,Thread类也是实现了Runnable接口。这两种方式在运行接收后都会被虚拟机销毁。如果线程数量多的话,频繁的创建和销毁就会大大的浪费时间和效率,而且会浪费内存。为了减少创建和销毁线程的次数,让每个线程可以多次使用,可根据系统情况调整执行的线程数量,防止消耗过多内存和是时间。
一个线程池包括以下四个基本部分:

  • 线程池管理器(ThreadPool) : 用于创建并管理线程池,包括销毁线程池和添加新任务
  • 工作线程(PoolWorker) : 线程池中线程,在没有任务时处于等待装态,主要循环执行的任务
  • 任务接口(Task) : 每个任务都必须实现的接口,以供工作线程调度任务的执行,主要规定了任务的入口,任务执行完后的收尾工作,以及任务的执行装态等
  • 任务队列(taskQueue) : 用于存放没有处理的任务。一种缓冲机制。

特点

  • 线程复用
  • 控制最大并发数量
  • 管理线程

优点

  • 降低了资源消耗。通过复用机制降低了线程的创建和销毁带来的消耗
  • 提高响应速度。当任务来临时,不需要等待创建线程的时间就能立即执行
  • 提高线程的管理。如果无限制的创建,不仅消耗系统资源,还会降低系统的稳定性,使用线程池可以统一分配,调优和控制

线程池配置说明

线程池的最上层接口是Executor,这个接口定义了一个核心方法execute(Runnable command),这个方法最后被ThreadPoolExecutor类实现,用来传入任务。而且ThreadPoolExecutor是线程池的核心类,此类构造方法如下:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }
  • corePoolSize:核心线程池的大小,如果核心线程池有空闲位置,这是新的任务就会被核心线程池新建一个线程执行,执行完毕后不会销毁线程,线程会进入缓存队列等待再次被运行。
  • maximumPoolSize:线程池能创建最大的线程数量。如果核心线程池和缓存队列都已经满了,新的任务进来就会创建新的线程来执行。但是数量不能超过maximunPoolSize,否侧会采取拒绝接受任务策略,我们下面会具体分析。
  • keepAliveTime:非核心线程能够空闲的最长时间,超过时间,线程终止。这个参数默认只有在线程数量超过核心线程池大小时才会起作用。只要线程数量不超过核心线程大小,就不会起作用。
  • unit:时间单位,和keepAliveTime配合使用。
  • workQueue:缓存队列,用来存放等待被执行的任务。
  • threadFactory:线程工厂,用来创建线程,一般有三种选择策略。
  • ArrayBlockingQueue
  • LinkedBlockingQueue
  • SynchronousQueue
  • handler:拒绝处理策略,线程数量大于最大线程数就会采用拒绝处理策略
  • ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
  • ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
  • ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
  • ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
  • 实现RejectedExecutionHandler接口,也可自定义处理器。

你可能感兴趣的:(SpringBoot 线程池的使用)