文章目录
前言
Executors和ThreadPoolExecutor和ThreadPoolTaskExecutor三种来讨论
一、Executors
1.Executors.newFixedThreadPool:创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待;
2.Executors.newCachedThreadPool:创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程;
3.Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执行顺序;
4.Executors.newScheduledThreadPool:创建一个可以执行延迟任务的线程池;
5.Executors.newSingleThreadScheduledExecutor:创建一个单线程的可以执行延迟任务的线程池;
6.Executors.newWorkStealingPool:创建一个抢占式执行的线程池(任务执行顺序不确定)【JDK 1.8 添加】
重点
Executors不推荐使用:
根据阿里巴巴规范:创建的线程池需要自己把控,而Executors生成的线程池不够灵活,可能会造成资源浪费,或者请求堆积
二、ThreadPoolExecutor
手动创建的线程池
构造方法:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {}
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {}
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {}
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {}
1.corePoolSize:核心线程数,长期存在的线程数
2.maximumPoolSize:最大线程数,最大存在的线程数
3.keepAliveTime:存活时长
4.unit:时长单位
5.threadFactory:⽤于生成线程,⼀般我们可以⽤默认的就可以了。
6.workQueue:任务队列,用于存储线程池的待执行任务的
7.handler:拒绝策略
拒绝策略
DiscardPolicy : 忽略旧任务(队列第一个任务)
AbortPolicy : 提示异常,拒绝执行(默认的拒绝策略)
CallerRunsPolicy : 使用调用线程池的线程来执行任务
DiscardOldestPolicy : 忽略最新任务
ThreadPoolExecutor使用方式
1.定义一个线程池
/**
* 任务线程池
*/
final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 12, 30,TimeUnit.SECONDS, new ArrayBlockingQueue(200),
(Runnable r, ThreadPoolExecutor executor)-> new ThreadPoolExecutor.AbortPolicy());
//定义了一个核心为2,最大长度为12,存活30秒,拒绝策略为抛异常的线程池
2.定义一个任务类
class AddTask implements Runnable{
String targetId;
String aiFunctionId;
String labelId;
String templateId;
String catalogId;
public AddTask(String targetId,String aiFunctionId,String labelId,String templateId,String catalogId){
this.targetId=targetId;
this.aiFunctionId=aiFunctionId;
this.labelId=labelId;
this.templateId=templateId;
this.catalogId=catalogId;
}
@Override
public void run() {
buildTask(targetId,aiFunctionId,labelId,templateId,catalogId);
}
}
//buildTask是具体的实现方法
3.线程池执行
threadPool.execute(new AddTask(mediaId,aiFunctionId,labelId,templateId,catalogId));
三.ThreadPoolTaskExecutor
与上两种jdk提供的不同,这种是spring提供的线程池,是对第二种线程池的封装
1.定义线程池
没有提供带参构造方法,更适合配置@Async使用
@Configuration
public class ExecturConfig {
@Bean("taskExector")
public Executor taskExector() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int i = Runtime.getRuntime().availableProcessors();//获取到服务器的cpu内核
executor.setCorePoolSize(5);//核心池大小
executor.setMaxPoolSize(100);//最大线程数
executor.setQueueCapacity(1000);//队列程度
executor.setKeepAliveSeconds(1000);//线程空闲时间
executor.setThreadNamePrefix("tsak-asyn");//线程前缀名称
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());//配置拒绝策略
return executor;
}
使用注解异步方法
@Async("taskExector")
public void buildTask(String targetId,String aiFunctionId,String labelId,String templateId,String catalogId){
}
使用自带的方法,和ThreadPoolExecutor方法一样,需要定义个task实现Runnable
threadPoolTaskExecutor.execute(new Runnable);
注意
@Async可能出现失效的问题:
含有@Async或@Transational注解的bean被spring扫描时,spring会为其生成一个代理类,代理类继承原来的目标bean,如果该注解作用在方法上,则会重写目标bean对应方法,将该方法做相应的增强(如果该注解是作用在类上,则会增强该类的所有方法)。而方法a不含@Async或@Transational,所以不会增强处理,所以方法a是直接调用方法b,导致@Async或@Transational失效。
解决方法:
1.将带有注解的方法写在另外一个类中
2.使用反射获取代理类的方法:
A a = context.getBean(A.class); //从spring容器中重新获取A的代理对象,再调用b方法注解即生效
a.bMethod();