线程池使用学习总结

什么是线程池?

线程池(ThreadPool)是一种基于池化思想管理和使用线程的机制。
它是将多个线程预先存储在一个“池子”内,当有任务出现时可以避免重新创建和销毁线程所带来性能开销,
只需要从“池子”内取出相应的线程执行对应的任务即可。

线程池优势:

➢ 降低资源消耗:通过池化技术重复利用已创建的线程,降低线程创建和销毁造成的损耗。

➢ 提高响应速度:任务到达时,无需等待线程创建即可立即执行。

➢ 提高线程的可管理性:线程是稀缺资源,如果无限制创建,不仅会消耗系统资源,还会因为线程的不合理
	分布导致资源调度失衡,降低系统的稳定性。使用线程池可以进行统一的分配、调优和监控。
	
➢ 提供更多更强大的功能:线程池具备可拓展性,允许开发人员向其中增加更多的功能。
	比如延时定时线程池ScheduledThreadPoolExecutor,就允许任务延期执行或定期执行。

在《阿里巴巴Java开发手册》中规定:线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。

线程池的创建

Executors

Executors为线程池工具类,相当于一个工厂类,用来创建合适的线程池,返回ExecutorService类型的线程池。
在《阿里巴巴Java开发手册》中也不允许直接使用Executors去创建线程池的。有如下方法。

➢ Executors.newFixedThreadPool:创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待;

➢ Executors.newCachedThreadPool:创建一个可缓存的线程池,若线程数超过处理所需,
					缓存一段时间后会回收,若线程数不够,则新建线程;

➢ Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执行顺序;

➢ Executors.newScheduledThreadPool:创建一个可以执行延迟任务的线程池;

➢ Executors.newSingleThreadScheduledExecutor:创建一个单线程的可以执行延迟任务的线程池;

➢ Executors.newWorkStealingPool:创建一个抢占式执行的线程池(任务执行顺序不确定)【JDK 1.8 添加】。

ThreadPoolExecutor

JDK自带的线程池,
new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, 
				TimeUnit.SECONDS, new SynchronousQueue<Runnable>());

ThreadPoolTaskExecutor (推荐)

ThreadPoolTaskExecutorSpring 框架提供的一个线程池实现,用于管理和执行多线程任务。
它是 TaskExecutor 接口的实现,提供了在 Spring 应用程序中创建和配置线程池的便捷方式。

➢ 使用ThreadPoolTaskExecutor 时一般需配置线程池

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置类
 * 
 * @author zhao-cj
 */
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {

    /**
     * 核心线程数(默认线程数)
     */
    private static final int CORE_POOL_SIZE = 20;

    /**
     * 最大线程数
     */
    private static final int MAX_POOL_SIZE = 100;

    /**
     * 允许线程空闲时间(单位:默认为秒)
     */
    private static final int KEEP_ALIVE_TIME = 10;

    /**
     * 缓冲队列大小
     */
    private static final int QUEUE_CAPACITY = 200;

    /**
     * 线程池名前缀
     */
    private static final String THREAD_NAME_PREFIX = "server-async-";

    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(CORE_POOL_SIZE);
        executor.setMaxPoolSize(MAX_POOL_SIZE);
        executor.setQueueCapacity(QUEUE_CAPACITY);
        executor.setKeepAliveSeconds(KEEP_ALIVE_TIME);
        executor.setThreadNamePrefix(THREAD_NAME_PREFIX);

        // 线程池对拒绝任务的处理策略
        // CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        // 初始化
        executor.initialize();
        return executor;
    }

}

或者在配置文件中配置

spring:
  task:
    execution:
      pool:
        core-size: 8
        max-size: 15
        queue-capacity: 100


# 自动装配类为org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
# 默认配置在org.springframework.boot.autoconfigure.task.TaskExecutionProperties

➢ 在使用多线程方法上标注@Async时表明调用的线程池

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 *
 * @author zhao-cj
 */
@Component
@Slf4j
public class AsyncTask {

    @Async("taskExecutor")
    public void execute() throws Exception {

        log.info("开始做任务");
        long start = System.currentTimeMillis();

        Thread.sleep(4000);

        long end = System.currentTimeMillis();

        log.info("完成任务,耗时:" + (end - start) + "毫秒");
    }

}

SimpleAsyncTaskExecutor

SimpleAsyncTaskExecutor也是Spring提供线程池,当使用@Async来开启多线程时,
未指定线程池情况下,默认使用的是就是 SimpleAsyncTaskExecutor。

simpleAsyncTaskExecutor的特点是,每次执行任务时,它会重新启动一个新的线程,
其并发线程的最大数量默认是concurrencyLimit取值为-1,即不启用资源节流。

线程池的七个参数详解

➢ corePoolSize:线程池中的线程数量;

➢ maximumPoolSize:线程池中的最大线程数量;

➢ keepAliveTime:当线程池线程数量超过corePoolSize时,多余的空闲线程会在多长时间内被销毁;

➢ unit:keepAliveTime的时间单位;

➢ workQueue:任务队列,被提交但是尚未被执行的任务;

➢ threadFactory:线程工厂,用于创建线程,一般情况下使用默认的,即Executors类的静态方法defaultThreadFactory();

➢ handler:拒绝策略,
	AbortPolicy(默认策略):这是默认的拒绝策略,
					它会抛出一个 RejectedExecutionException 异常,表示任务被拒绝执行。
					
	CallerRunsPolicy: 当线程池已满时,将任务返回给提交任务的调用者(Caller)。
		这意味着提交任务的线程会尝试执行被拒绝的任务。
		
	DiscardPolicy: 这个策略会默默地丢弃被拒绝的任务,不会产生任何异常。
	
	DiscardOldestPolicy: 这个策略会丢弃队列中最老的任务,然后尝试将新任务添加到队列中。

修改 @Async 配置默认线程池

在使用 @Async 时,每次都要指定自定义的线程池比较麻烦,可以直接修改其置默认线程池

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 描述:异步配置
 *	注意:@EnableAsync 可放在启动类上或单独的配置类
 *	
 * @author zhao-cj
 */
@Slf4j
@Configuration
@EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {

    @Bean(name = "asyncPoolTaskExecutor")
    public ThreadPoolTaskExecutor executor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();

        //核心线程数
        taskExecutor.setCorePoolSize(10);

        //线程池维护线程的最大数量,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        taskExecutor.setMaxPoolSize(100);

        //缓存队列
        taskExecutor.setQueueCapacity(50);

        //设置线程的空闲时间,当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
        taskExecutor.setKeepAliveSeconds(200);

        //异步方法内部线程名称
        taskExecutor.setThreadNamePrefix("async-");

        /**
         * 当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略
         * 通常有以下四种策略:
         * ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
         * ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
         * ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
         * ThreadPoolExecutor.CallerRunsPolicy:重试添加当前的任务,自动重复调用 execute() 方法,直到成功
         */
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        taskExecutor.initialize();
        return taskExecutor;
    }

    /**
     * 指定默认线程池
     */
    @Override
    public Executor getAsyncExecutor() {
        return executor();
    }

    /**
     * 在异步方法执行过程中引发异常时执行
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (ex, method, params) -> log.error("线程池执行任务发送未知错误, 执行方法:{}", method.getName(), ex);
    }
}

你可能感兴趣的:(学习,java,spring)