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密集型
]]>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
的方法是不生效的