• 关于ThreadPoolTaskExecutor线程池的配置


    说明:
    1、线程池分类、其他

    1.1、分类
    IO密集型 和 CPU密集型 任务的特点不同,因此针对不同类型的任务,选择不同类型的线程池可以获得更好的性能表现。

    1.1. IO密集型任务

    ​ IO密集型任务的特点是需要频繁读写磁盘、网络或者其他IO资源,执行时间长,CPU占用率较低。

    对于这类任务,线程的执行时间主要取决于IO操作的速度,而非CPU的执行能力。

    ​ 因此,线程池的线程数应该设置较大,以便充分利用IO资源。

    通常建议使用CachedThreadPool线程池或者FixedThreadPool线程池来处理IO密集型任务。

    1.2. CPU密集型任务

    ​ CPU密集型任务的特点是需要进行大量的计算,执行时间长,CPU占用率较高。

    对于这类任务,线程的执行时间主要取决于CPU的执行能力。

    ​ 因此,线程池的线程数应该设置较小,以充分利用CPU的计算能力,避免过多的线程切换和上下文切换导致的性能损失。

    通常建议使用FixedThreadPool线程池或者SingleThreadPool线程池来处理CPU密集型任务。

    1.2. 异步线程池的选择
    对于异步线程池,通常建议使用IO密集型线程池。
    异步任务通常是网络IO或磁盘IO等操作,这些操作的执行时间相对于CPU计算的执行时间要长得多。
    使用IO密集型线程池可以更好地利用IO资源,提高多个异步任务的执行效率和吞吐量,
    同时避免由于过多的线程切换和上下文切换导致的性能损失。

    1.3. 线程池工作步奏
    很多任务——》线程池创建核心线程——》任务超过最大线程——》把任务放入队列中等待执行——》队列中放满了——》进入处理策略

    /**
     * @Description: 线程池配置
     */
    @Configuration
    @EnableAsync
    public class ThreadPoolConfig {
    
    	/**
    	 * 打印日志
    	 */
    	private Logger logger = LoggerFactory.getLogger(getClass());
    
    	/**
    	 * cpu 核心数量
    	 */
    	public static final int cpuNum = Runtime.getRuntime().availableProcessors();
    
    	/**
    	 * 线程池配置
    	 *
    	 * @return
    	 */
    	@Bean("taskExecutor")
    	public TaskExecutor taskExecutor() {
    		ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    		// 核心线程数:当线程池中的线程数量为 corePoolSize 时,即使这些线程处于空闲状态,也不会销毁(除非设置 allowCoreThreadTimeOut=true)。
    		// -> 核心线程,也就是正在处理中的任务
    		// -> 虽然 CPU 核心数可以作为线程池中线程数量的参考指标,但最终线程数量还需要根据具体情况进行设置和调整。
    		// -> 如果同时运行的线程数量超过 CPU 核心数,就会发生--线程上下文切换--,导致额外的开销和性能下降。所以线程不能创建得过多
    		taskExecutor.setCorePoolSize(cpuNum);
    		//  IO密级 :2 * N   CPU密级:1 + N
    		//  最大线程数:线程池中允许的线程数量的最大值。
    		//-> 当线程数 = maxPoolSize最大线程数时,还有新任务,就会放进队列中等待执行 ↓↓↓
    		taskExecutor.setMaxPoolSize(2 * cpuNum);
    		// 队列长度:当核心线程数达到最大时,新任务会放在队列中排队等待执行
    		// -> 根据业务配置,如果队列长度过大,可能会导致系统内存资源占用过高,最终导致 OOM,需要注意控制
    		// -> 如果需要执行的任务装满了队列,就会走拒绝策略 ↓↓↓
    		taskExecutor.setQueueCapacity(500);
    		// 当前线程池的等待时间:指等待所有任务执行完毕后线程池的最长时间。300秒 = 5分钟
    		// -> 当所有任务执行完毕后,线程池会等待一段时间(即等待时间),来确保所有任务都已经完成。
    		// -> 如果在等待时间内所有任务仍未完成,则线程池会强制停止,以确保任务不会无限制地执行下去。
    		taskExecutor.setAwaitTerminationSeconds(300);
    		//空闲线程存活时间(默认60s):设置当前线程池中空闲线程的存活时间,即线程池中的线程如果有一段时间没有任务可执行,则会被回收掉。
    		// -> 当线程池中的线程数大于 corePoolSize 时,多余的空闲线程将在销毁之前等待新任务的最长时间。
    		// -> 如果一个线程在空闲时间超过了 keepAliveSeconds,且当前线程池中线程数量大于 corePoolSize,则该线程将会被回收;
    		// -> 核心线程会一直存活,除非线程池被关闭 或 设置下面的参数
    		// -> 如果 AllowCoreThreadTimeout设置为true,核心线程也会被回收,直到线程池中的线程数降为 0。
    		// 但如果线程池中有任务在执行,那么空闲线程就会一直保持存活状态,直到任务执行完毕。
    		// -> 该方法的使用可以将线程池的空闲线程回收,以减少资源占用,同时也能保证线程池中始终有可用的线程来执行任务,提高线程池的效率。
    		taskExecutor.setKeepAliveSeconds(60);
    		// 当前线程池是否在关闭时等待所有任务执行完成
    		//-> 可以确保所有任务都执行完毕后才关闭线程池,避免任务被丢弃,同时也确保线程池可以正常结束,释放资源。
    		//-> 为 true 时,线程池在关闭时会等待所有任务都执行完成后再关闭
    		//-> 为 false 时,线程池会直接关闭,未执行完成的任务将被丢弃。
    		taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
    		// 是否禁止线程池自动终止空闲的核心线程。
    		// 为 true 时,空闲的核心线程会在 keepAliveTime 时间后被回收,并且在后续任务到来时需要重新创建线程来执行任务。
    		// 为 false 时,线程池中的核心线程不会被回收,即使它们处于空闲状态一段时间。
    		// -> 在线程池创建时,就会预先创建核心线程数的线程,这些线程将一直存在,除非线程池被关闭或重新配置。
    		taskExecutor.setAllowCoreThreadTimeOut(true);
    		//设置拒绝处理的策略(当线程池无法处理新的任务时,该执行什么策略)
    		//new ThreadPoolExecutor.CallerRunsPolicy() 该策略为选择调用者线程进行处理
    		//new ThreadPoolExecutor.AbortPolicy() 该策略为丢弃任务并抛出RejectedExecutionException异常(不设置时默认此策略)
    		//new ThreadPoolExecutor.DiscardPolicy() 该策略为丢弃任务,但是不抛异常
    		//new ThreadPoolExecutor.DiscardOldestPolicy() 该策略为丢弃队列最前面的任务,然后重新尝试执行任务
    		taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
    		// 线程池名称前缀
    		taskExecutor.setThreadNamePrefix("thread-pool-");
    		// 线程池初始化
    		taskExecutor.initialize();
    		logger.info("线程池初始化......");
    		return taskExecutor;
    	}
    
    	//使用方法
    	//private final TaskExecutor taskExecutor;
    	//taskExecutor.execute(() -> doYourMethod());
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
  • 相关阅读:
    (WebFlux)004、WebFilter踩坑记录
    1w5字详细介绍分布式系统的那些技术方案
    12个球,有一个与其他不一样,提供一个天平,三次找出来
    《Vue入门到精通系列之五》--- vue-router详解
    想读项目源码?可为什么总是读不下去?
    并查集拓展(扩展域并查集)
    apache-atlas-hive-bridge-源码分析
    【疯壳·平板教程3】手把手教你做平板电脑-LCD 驱动实验教程
    java的file类的常用的操作实战分享来啦
    网页设计前端作品(大一)HTML+CSS
  • 原文地址:https://blog.csdn.net/qq_37741426/article/details/132718184