目录
一:使用线程池有什么优点
- 线程池中线程的使用率提升,减少对象的创建、销毁;
- 线程池可以控制线程数,有效的提升服务器的使用资源,避免由于资源不足而发生宕机等问题;
二:线程池的七个参数
- maximumPoolSize:最大线程数目 (最大线程数目 = 核心线程数目 + 救急线程数目)
- corePoolSize:核心线程数(最多保留的线程数目)
- keepAliveTime:生存时间(针对救急线程)
- unit:时间单位(针对救急线程)
- ThreadFactory:线程工厂(给线程取名字)
- WorkQueue:阻塞队列
- handler:拒绝策略
什么时候使用救急线程?
核心线程数目用完后,阻塞队列满了之后
三:使用Executor工厂类
Executors是一个工厂类,采用工厂模式可以方便的创建各种类型Executor线程池(4种)
1:单线程的线程池:newSingleThreadExecutor()
Executors.newSingleThreadExecutor()
特点:
- 创建一个Executor,顺序执行一个任务队列,每次只能执行一个任务。
- 如果线程任务执行失败,单线程线程池会新建一个线程继续下一个任务
- 使用场景:希望多个任务排队执行
2:固定大小线程池:newFixedThreadPool
Executors.newFixedThreadPool(5); //创建线程数目为5的线程池
特点:
- 核心线程数 = 最大线程数
- 阻塞队列是无界的,可以让任意数量的任务
3:带缓冲的线程池:newCachedThreadPool()
Executors.newCachedThreadPool();
特点:
- 线程数目会随任务数目增加而增加,同时也会回收已经空闲的线程。
- 核心线程数目为0,最大线程数为int的最大值,
- 创建的全部是救急线程,生存时间为60S
- 阻塞队列没有容量
4:周期性执行的线程池:newScheduledThreadPool
Executors.newScheduledThreadPool(5000);
特点
- 该线程池支持定时,以及周期性的任务执行,
- 我们可以延迟任务的执行时间,也可以设置一个周期性的时间让任务重复执行。
线程池常见方法
- submit:在主线程中接受线程池中线程返回的结果
- execute:执行线程池中任务
- invokeAny:将线程池中任务全部执行,返回最先执行完的任务,其他任务取消
- invokeAll:将线程池中任务全部执行
- shutdown:关闭线程池,不会接受新任务,但会将剩余任务执行完
- shutdownNow:立即关闭线程池,返回线程中任务
四:Spring Boot自定义线程池
- @Async注解:使用系统默认或者 自定义的线程池
- @EnableAsync注解:开启异步线程支持
@Configuration
@EnableAsync //开启异步线程支持
public class ThreadPoolConfig {
@Bean("taskExecutor") //注入Bean容器,给线程池取名字
public Executor asyncServiceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//参数一:设置最大线程数
executor.setMaxPoolSize(20);
//参数二:设置核心线程数
executor.setCorePoolSize(5);
//参数三:配置阻塞队列大小
executor.setQueueCapacity(Integer.MAX_VALUE);
//参数四五:设置线程活跃时间(秒)
executor.setKeepAliveSeconds(60);
//参数六:设置默认线程名称
executor.setThreadNamePrefix("小苏打博客项目");
//等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
//执行初始化
executor.initialize();
return executor;
}
}
配置线程池
@Component
public class ThreadService {
/*
updateArticleViewCount 的实现
期望此操作在线程池,不能影响主线程
*/
@Async("taskExecutor") //指定使用 taskExecutor 线程池
public void updateArticleViewCount(ArticleMapper articleMapper, Article article) {
int viewCounts = article.getViewCounts();
Article articleUpdate = new Article();
articleUpdate.setViewCounts(viewCounts+1);
LambdaQueryWrapper<Article> updateWrapper = new LambdaQueryWrapper<>();
updateWrapper.eq(Article::getId,article.getId());
updateWrapper.eq(Article::getViewCounts,viewCounts);
articleMapper.update(articleUpdate,updateWrapper);
}
}
使用线程池