知了小站 - IT人的小站 - 线程池 https://www.ydyno.com/tag/ExecutePool/ Java开发,配置线程池时线程数应该怎么设置 https://www.ydyno.com/archives/1555.html 2022-05-20T16:41:00+08:00 合理的设置线程数能有效提高 CPU 的利用率,设置线程数又得区分任务是CPU密集型还是 IO密集型。解释CPU密集型 就是需要大量进行计算任务的线程,如:计算1+2+3+...、计算圆周率、视频解码等,这种任务本身不太需要访问I/O设备,CPU的使用率高;IO密集型 就是任务运行时大部分的时间都是CPU在等I/O (硬盘/内存) 的读/写操作,如:查询数据库、文件传输、网络请求等,CPU的使用率不高。根据经验1、CPU密集型:线程数少一点,推荐:CPU内核数 + 1 2、IO密集型:线程数多一些,推荐:CPU内核数 * 2 3、混合型:可以将CPU密集和IO密集的操作分成两个线程池去执行即可!PS:这种方式可能会被面试官找茬根据计算公式根据《Java并发编程实战》书中的计算线程数的公式Ncpu = CPU的数量 Ucpu = 目标CPU的使用率, 0 <= Ucpu <= 1 W/C = 等待时间与计算时间的比率 为保持处理器达到期望的使用率,最优的池的大小等于: Nthreads = Ncpu x Ucpu x (1 + W/C)实战假如在一个请求中,计算操作需要10ms,DB操作需要100ms,对于一台2个CPU的服务器,设置多少合适假设我们需要CPU的使用率达到100%,那么套入公式:`2 x 1 x (1 + 100/10) = 22`但是实际开发中,可能有各种因素的影响,因此就需要我们在这个结果的基础上进行压力测试,最终得到一个完美的线程数量最后补个网图,解释了CPU密集型、IO密集型 Spring Boot 自定义异步线程池的两种方式 https://www.ydyno.com/archives/1199.html 2019-11-06T14:08:00+08:00 SpringBoot 使用异步线程池方式如下第一种创建自定义线程池配置类,AsyncTaskExecutePool@EnableAsync @Configuration public class AsyncTaskExecutePool { //核心线程池大小 private final int corePoolSize = 10; //最大线程数 private final int maxPoolSize = 15; //队列容量 private final int queueCapacity = 50; //活跃时间/秒 private final int keepAliveSeconds = 60; @Bean public Executor myAsyncTaskPool() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //核心线程池大小 executor.setCorePoolSize(corePoolSize); //最大线程数 executor.setMaxPoolSize(maxPoolSize); //队列容量 executor.setQueueCapacity(queueCapacity); //活跃时间 executor.setKeepAliveSeconds(keepAliveSeconds); //设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean executor.setWaitForTasksToCompleteOnShutdown(true); //线程名字前缀 executor.setThreadNamePrefix("my-async1--"); // setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务 // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } }创建任务处理类AsyncTask@Component @Slf4j public class AsyncTask { /** * myAsyncTaskPool 线程池的方法名,此处如果不写,会使用Spring默认的线程池 * @param i */ @Async("myAsyncTaskPool") public void run(int i){ log.info("我是:" + i); } }测试线程池AppTests@SpringBootTest class AppTests { @Autowired private AsyncTask asyncTask; @Test void test(){ for (int i = 0; i < 100; i++) { asyncTask.run(i); } } } 运行查看效果第二种第二种方式是重写 spring 默认线程池,使用这种方式的好处是可以直接使用 @Async 注解创建配置类AsyncTaskExecutePool1 并且实现AsyncConfigurer 类@Slf4j @EnableAsync @Configuration public class AsyncTaskExecutePool1 implements AsyncConfigurer { //核心线程池大小 private final int corePoolSize = 10; //最大线程数 private final int maxPoolSize = 15; //队列容量 private final int queueCapacity = 50; //活跃时间/秒 private final int keepAliveSeconds = 60; @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //核心线程池大小 executor.setCorePoolSize(corePoolSize); //最大线程数 executor.setMaxPoolSize(maxPoolSize); //队列容量 executor.setQueueCapacity(queueCapacity); //活跃时间 executor.setKeepAliveSeconds(keepAliveSeconds); //设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean executor.setWaitForTasksToCompleteOnShutdown(true); //线程名字前缀 executor.setThreadNamePrefix("my-async-"); // setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务 // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } /** * 异步任务异常处理 * @return */ @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return (throwable, method, objects) -> { log.error("===="+throwable.getMessage()+"====", throwable); log.error("exception method:"+method.getName()); }; } }修改AsyncTask 类,在类中加入方法run1@Async public void run1(int i){ log.info("我是:" + i); }测试,在AppTests 中加入方法test1@Test void test1(){ for (int i = 0; i < 100; i++) { asyncTask.run1(i); } }运行查看效果注意同类中调用带有@Async 的方法是不生效的例子中的参数根据具体的需求修改源码本文源码:https://github.com/elunez/spring-boot-learn