以下摘自阿里开发手册原话
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors各个方法的弊端:
1)newFixedThreadPool和newSingleThreadExecutor:
主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
2)newCachedThreadPool和newScheduledThreadPool:
主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。
阿里推荐线程池
-
Positive example 1(commons.lang3):
//org.apache.commons.lang3.concurrent.BasicThreadFactory ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
-
Positive example 2(guava):
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder() .setNameFormat("demo-pool-%d").build(); //Common Thread Pool ExecutorService pool = new ThreadPoolExecutor(5, 200, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); pool.execute(()-> System.out.println(Thread.currentThread().getName())); pool.shutdown();//gracefully shutdown
-
Positive example 3(spring异步任务线程池):
<bean id="userThreadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <property name="corePoolSize" value="10" /> <property name="maxPoolSize" value="100" /> <property name="queueCapacity" value="2000" /> <property name="rejectedExecutionHandler"> <ref local="rejectedExecutionHandler" /> </property> </bean> //in code userThreadPool.execute(thread);
自己开发使用
- commons.lang3
package com.staryea.invocate.util; import com.google.common.util.concurrent.ThreadFactoryBuilder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import java.util.concurrent.*; /** * @author: hs * @Date: 2019/3/30 15:12 * @Description: */ @Slf4j public class ThreadPoolHelper { /** * 线程池大小 */ private static final int POOL_SIZE = 6; private static final String THREAD_NAME = "invocation-list-pool-%d"; /** * 避免资源浪费的情况,懒加载。 * private static ExecutorService pool = new ThreadPoolExecutor(5, 200, * 0L, TimeUnit.MILLISECONDS, * new LinkedBlockingQueue<Runnable>(1024), threadFactory(), * new ThreadPoolExecutor.AbortPolicy()); */ private static class ThreadPool{ /** * lang3线程池配置类,配置线程池 */ private static ThreadPoolExecutor comitTaskPool = new ScheduledThreadPoolExecutor(POOL_SIZE, new BasicThreadFactory.Builder().namingPattern(THREAD_NAME).daemon(true).build()); /** * guava线程工厂 */ private static ThreadFactory threadFactory = new ThreadFactoryBuilder() .setNameFormat(THREAD_NAME).build(); } /** * * @return */ public static ThreadFactory threadFactory(){ return ThreadPool.threadFactory; } /** * * @return */ private static ThreadPoolExecutor threadPool(){ return ThreadPool.comitTaskPool; } /** * 执行任务 * 默认5个线程池执行任务 * * @param comitTask */ public static void executeTask(Runnable comitTask) { threadPool().execute(comitTask); log.debug("【线程池任务】线程池中线程数:" + threadPool().getPoolSize()); log.debug("【线程池任务】队列中等待执行的任务数:" + threadPool().getQueue().size()); log.debug("【线程池任务】已执行完任务数:" + threadPool().getCompletedTaskCount()); } /** * 指定线程池长度执行线程 * * @param poolSize * @param comitTask */ public static void executeTask(int poolSize, Runnable comitTask) { threadPool().setCorePoolSize(poolSize); executeTask(comitTask); log.debug("【线程池任务】线程池中线程数:" + threadPool().getPoolSize()); log.debug("【线程池任务】队列中等待执行的任务数:" + threadPool().getQueue().size()); log.debug("【线程池任务】已执行完任务数:" + threadPool().getCompletedTaskCount()); } /** * 关闭线程池 */ public static void shutdown() { log.debug("shutdown comitTaskPool..."); threadPool().shutdown(); try { if (!threadPool().isTerminated()) { log.debug("直接关闭失败[" + threadPool().toString() + "]"); threadPool().awaitTermination(3, TimeUnit.SECONDS); if (threadPool().isTerminated()) { log.debug("成功关闭[" + threadPool().toString() + "]"); } else { log.debug("[" + threadPool().toString() + "]关闭失败,执行shutdownNow..."); if (threadPool().shutdownNow().size() > 0) { log.debug("[" + threadPool().toString() + "]没有关闭成功"); } else { log.debug("shutdownNow执行完毕,成功关闭[" + threadPool().toString() + "]"); } } } else { log.debug("成功关闭[" + threadPool().toString() + "]"); } } catch (InterruptedException e) { log.warn("接收到中断请" + threadPool().toString() + "停止操作"); } } }
- spring异步任务
-
引入依赖开启yml文件自动提示功能
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <!--<optional>true</optional>--> </dependency>
-
spring异步任务线程池配置
import static org.apache.commons.lang3.StringUtils.defaultIfBlank; /** * @author: hs * @Date: 2019/3/18 09:37 * @Description: */ @Configuration @EnableAsync @EnableConfigurationProperties(AsyncTaskConfig.AsyncTaskProperties.class) public class AsyncTaskConfig { @Bean public AsyncTaskExecutor asyncTaskExecutor(AsyncTaskProperties asyncTaskProperties) { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setThreadNamePrefix(defaultIfBlank(asyncTaskProperties.threadNamePrefix,"invocation-list-")); executor.setMaxPoolSize(toInt(asyncTaskProperties.getMaxPoolSize(), 10)); executor.setCorePoolSize(toInt(asyncTaskProperties.getCorePoolSize(), 5)); executor.setQueueCapacity(toInt(asyncTaskProperties.getQueueCapacity(), 20)); //若没有空闲的线程,则把任务抛给主线程去执行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); return executor; } @Data @ConfigurationProperties("spring.async") public static class AsyncTaskProperties { private Integer maxPoolSize; private Integer corePoolSize; private Integer queueCapacity; private String threadNamePrefix; } /** * @param num * @param defaultNum * @return */ private int toInt(Integer num, int defaultNum) { return Objects.equal(num, null) ? defaultNum : num; } }
-
yml文件配置(此配置文件也可以不配置,会自动使用配置类中默认配置)
spring: async: core-pool-size: 6 max-pool-size: 15 queue-capacity: 50
-
使用
@Slf4j @Service public class ServerCalculateServiceImpl extends JestBaseDao implements ServerCalculateService { @Async @Override public void asyncInsertServerCalculates(List<ServerCalculate> list) { LocalDate now = LocalDate.now(); this.batchDocument(list, JestConsts.Index.CALL_LIST.getIndexName().concat(now.toString()), JestConsts.Index.CALL_LIST.getIndexType()); } }
多模块分离情况下,可在启动类上加入如下注解(可以用其他方式,仅供参考):
/** * 异步任务 * @author hs */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import({AsyncTaskConfig.class}) public @interface EnableAsyncTask { }