为什么推荐使用ThreadPoolExecutor创建线程池

《阿里巴巴 Java 开发手册》“并发处理”这一章节,明确指出线程资源必须通过线程池提供,不允许在应用中自行显示创建线程。
另外《阿里巴巴 Java 开发手册》中强制线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 构造函数的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险

Executors 返回线程池对象的弊端如下:

  • FixedThreadPoolSingleThreadExecutor : 允许请求的队列长度为 Integer.MAX_VALUE,可能堆积大量的请求,从而导致 OOM。
  • CachedThreadPoolScheduledThreadPool : 允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致 OOM。

创建线程池

TreadPoolTaskExecutor.java

@Bean("executor")  
public ThreadPoolTaskExecutor authorLayerTaskExecutor(){  
    ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();  
    // 核心线程数  
    threadPool.setCorePoolSize(5);  
    // 最大线程数  
    threadPool.setMaxPoolSize(20);  
    // 线程存活时间  
    threadPool.setKeepAliveSeconds(5);  
    //线程池队列容量
    threadPool.setQueueCapacity(2000);  
    // 线程池前缀  
    threadPool.setThreadNamePrefix("authorLayerTask-log-pool-");  
    // 拒绝策略, 调用者执行  
    threadPool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());  
    threadPool.initialize();  
    return threadPool;  
}

参数

  • corePoolSize:核心线程数线程数定义了最小可以同时运行的线程数量。
    maximumPoolSize:当队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。
  • workQueue:当新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中。
  • keepAliveTime:当线程池中的线程数量大于 corePoolSize 的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了 keepAliveTime才会被回收销毁;
  • unit : keepAliveTime 参数的时间单位。

饱和策略

  • ThreadPoolExecutor.AbortPolicy:抛出 RejectedExecutionException来拒绝新任务的处理。
  • ThreadPoolExecutor.CallerRunsPolicy:调用执行自己的线程运行任务,也就是直接在调用execute方法的线程中运行(run)被拒绝的任务,如果执行程序已关闭,则会丢弃该任务。因此这种策略会降低对于新任务提交速度,影响程序的整体性能。如果您的应用程序可以承受此延迟并且你要求任何一个任务请求都要被执行的话,你可以选择这个策略。
  • ThreadPoolExecutor.DiscardPolicy 不处理新任务,直接丢弃掉。
  • ThreadPoolExecutor.DiscardOldestPolicy 此策略将丢弃最早的未处理的任务请求。

使用线程池

@Resource(name="executor")
private TreadPoolTaskExecutor executor

public void TreadPoolDemo(){
    for(int i=0;i<10;i++){
	    executor.submit(()->{
			System.out.println("use TreadPool");
			});
	}
	
}