前言
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.定义一个任务类
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);
}
}
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();
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);
a.bMethod();
|