1.说明
*这都是我想的,可能不是都对,如有纰漏,还望指正
1)线程池,线程池根据配置,允许最大n个线程同时执行
2)序列,就像一个list一样,但是它里面放的是一个Thread对象,线程池会从序列中取任务线程,然后执行
3)此次需求是现有订单,需要调用三方接口查询状态,所有大致思路是:
1).定时任务查出需要验证的订单
2).加入到线程序列中
3).如果序列中有需要执行的,线程池来处理
2.步骤
(0).创建一个配置类
在后面用得到,需要从中取注入spring的service等,替代@Resource
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class BeanContext implements ApplicationContextAware {
// Spring应用上下文环境
private static ApplicationContext applicationContext;
/*
* 实现了ApplicationContextAware 接口,必须实现该方法;
* 通过传递applicationContext参数初始化成员变量applicationContext
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanContext.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException {
return (T)applicationContext.getBean(name);
}
public static <T> T getBean(Class<T> clz) throws BeansException {
return (T)applicationContext.getBean(clz);
}
}
(1).创建线程池与序列
我创建在了一个新的配置类中,你也可以放在启动类里
先创建序列,然后创建线程,传入创建的序列与线程池关联,来看下创建线程池的几个关键参数
参数 | 解释 |
corePoolSize | 核心线程池大小,我理解为最大并行线程数 |
maximumPoolSize | 最大线程池大小 |
keepAliveTime | 线程最大空闲时间 |
TimeUnit.SECONDS | 时间(秒)这个我也没仔细查干什么用的 |
blockingQueue | 对应序列 |
代码如下
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Slf4j
@Configuration
public class ThreadPoolConfig {
/**
* 创建序列
* @return queue
*/
@Bean(name = "orderCheckQueue")
public ArrayBlockingQueue<Runnable> orderCheckQueue(){
ArrayBlockingQueue<Runnable> objects = new ArrayBlockingQueue<>(5000);
log.info("订单验证序列初始化完成");
return objects;
}
/**
* 创建线程池
* @param blockingQueue queue
* @return pool
*/
@Bean(name = "orderCheckThreadPool")
public ThreadPoolExecutor orderCheckThreadPool(@Qualifier(value = "orderCheckQueue") ArrayBlockingQueue<Runnable> blockingQueue){
int corePoolSize = 8;
int maximumPoolSize = 32;
long keepAliveTime = 60;
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, blockingQueue);
threadPoolExecutor.prestartAllCoreThreads();
log.info("订单验证线程池初始化完成");
return threadPoolExecutor;
}
}
(2)创建线程执行对象
线程执行对象里不能用@Resource
@Autowired
,需要使用构造方法注入,并从springContext中取service对象
XOrderInfoDao是一个mapper,演示注入方法
XOrderInfoEntity这个对象是我的订单类,这里传进来然后在run()
方法中执行验证验证订单的步骤
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class OrderVerifyExecutors implements Runnable{
XOrderInfoEntity order;
/*使用构造方法注入service*/
private final XOrderInfoDao orderInfoDao;
/*构造方法中操作service*/
public OrderVerifyExecutors(XOrderInfoEntity order){
this.order = order;
this.orderInfoDao = BeanContext.getApplicationContext().getBean(XOrderInfoDao.class);
}
@Override
public void run() {
xxx
//线程该执行的事情
}
}
(3)其实到这里就已经OK了,线程池有了,序列有了,线程执行方法也配置了,只要药使用定时任务,将XOrderInfoEntity对象添加到序列就可以了,这里使用定时任务,如下
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Profile;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
@Slf4j
@Component
//@Profile("beta")//只在生产环境启动
public class DalOrderJob {
//注入解析序列
@Resource(name = "orderCheckQueue")
private ArrayBlockingQueue<Runnable> orderCheckQueue;
@Resource
private XOrderInfoDao orderInfoDao;
@Scheduled(cron = "1 0/5 * * * ?")
public void methodRun() {
//查出订单,循环创建OrderVerifyExecutors执行对象,并添加到序列
List<XOrderInfoEntity> all = orderInfoDao.findAll();
all.forEach(item -> {
orderCheckQueue.add(new OrderVerifyExecutors(item));
});
}
}
需要注意的是,如果序列满了,就会添加不进去,会报错,需要添加前判断满没有,满了就sleep(),等会儿再加,我这里需要检查的订单量并不是很多,先不加了
如需转载,请附上原文地址如过你有问题,或者文章有问题,欢迎探讨指正