目录
(5)ThreadPoolExecutor 和 ThreadPoolTaskExecutor 怎么选
前言
线程池,顾名思义,可以类比一个水池,而每一个线程,都好比水池的水。因此,水池多大,看系统硬件配置,此处不多赘述。
当然,关于线程池大小的设定,也有其他开发者对此做出了建议:
线程池大小的设置
针对这个问题,我们首先要确认的是我们的需求是计算密集型还是IO密集型。
如果是计算密集型,比较理想的方案是:线程数 = CPU核数 + 1,也可以设置成CPU核数*2,一般设置CPU*2
如果是IO密集型,线程数 = CPU核心数/(1-阻塞系数),这个组赛系数一般为0.8~0.9之间,也可以取0.8或者0.9.
————————————————
版权声明:本文为CSDN博主「one_smail」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40386113/article/details/127581333
(1)@EnableAsync 和 @Async 很关键
@EnableAsync // 这注解允许异步
@Async // 这注解的函数会被异步处理
线程池的作用,很大程度上是为了并发,高效处理任务。而异步处理任务,可以有效提高处理任务的吞吐量。
(2)Thread 和 Runnable 要谨慎
Thread同样可以创建线程,但是线程使用完之后需要对线程资源进行销毁回收,这本身对资源的消耗不小,且容易造成线程上下文切换问题,甚至线程管理不当容易造成资源耗尽。因此需要使用线程时,要谨慎选择Thread。
(3)数据类型,线程安全 要牢记
如果有多线程共享数据的方式,要牢记各种使用场景的线程安全数据类型。如:
- AtomicInteger 原子int整型;
- AtomicLong 原子long整型;
- AtomicBoolean 原子boolean;
- List 这三种都是线程安全型:
- List<T> vector = new Vector<>();
- List<T> listSyn = Collections.synchronizedList(new ArrayList<>());
- List<T> copyList = new CopyOnWriteArrayList<>();
(4)@Configuration 和 @Bean 很方便
@Configuration 注解的配置类
@Bean 将实例对象提交给IoC容器
这对组合的搭配,让我们可以将实例对象的管理忽略,将更多的心思放在业务开发上。
值得点出来的还有 @Autowired(required = true) 自动装配实例对象;如果你不想自动装配,则 required = false。
(5)ThreadPoolExecutor 和 ThreadPoolTaskExecutor 怎么选
首先这两种线程池方式,本质上一样,ThreadPoolTaskExecutor 源码上是在 ThreadPoolExecutor 上再加了一层包装,为了更方便在spring框架中使用。而这里只讲ThreadPoolTaskExecutor。
(6)上才艺!
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
@EnableAsync
@Configuration
public class ThreadPoolCfg {
// 获取服务器的cpu个数
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// 核心线程数量
private static final int COUR_SIZE = CPU_COUNT * 2;
// 线程最大数量
private static final int MAX_COUR_SIZE = COUR_SIZE * 4;
// 提交给IoC容器,装配名称为 "threadPoolTaskExecutor"
@Bean("threadPoolTaskExecutor")
public ThreadPoolTaskExecutor taskExecutor(){
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
// 核心线程数量
threadPoolTaskExecutor.setCorePoolSize(COUR_SIZE);
// 最大线程数
threadPoolTaskExecutor.setMaxPoolSize(MAX_COUR_SIZE);
// 线程缓冲任务队列
threadPoolTaskExecutor.setQueueCapacity(MAX_COUR_SIZE * 2);
// 线程空闲时间
threadPoolTaskExecutor.setKeepAliveSeconds(60);
// 线程名称前缀
threadPoolTaskExecutor.setThreadNamePrefix("taskExecutor-");
// 线程拒绝任务处理策略:没精力处理时,直接拒绝任务;若执行程序已被关闭,则直接丢弃
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return threadPoolTaskExecutor;
}
}
// 这是个测试
public void test() {
for (int i = 0; i < 10; i++){
taskExecutor.execute(this::do_test);
}
System.out.println("main thread:" + Thread.currentThread().getName());
}
@Async("threadPoolTaskExecutor")
public void do_test() {
System.out.println("thread name:" + Thread.currentThread().getName());
}
以下则是测试结果,可以很明显看到线程的不同。