需求
我在做一个导入功能,导入的逻辑都是调用的页面接口。
接口执行逻辑:将数据保存到数据库,然后再调用job任务加工历史数据。
用户在页面上操作是OK的,毕竟每操作一下,接口最多调用一次。
但是导入就不一样了,相当于用户一直在对着页面点点点~这会导致后面历史任务的加工出现问题。
解决
在导入的时候,我需要先让基本数据保存到数据库就OK,等所有导入都完成后,我再一并去加工历史任务。
所以,设定一个延迟任务,要求30秒后我再去执行历史任务加工。
延时线程池
// 线程池定义
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
scheduledExecutorService.schedule(new TriggerProcessTask(fx, dms, taskParams), 30000, TimeUnit.MILLISECONDS);
任务类:TriggerProcessTask
public class TriggerProcessTask implements Runnable{
private ZkZxsjfx fx;
private List<String> dms;
private Map<String, String> bizParams;
public TriggerProcessTask() {
}
public TriggerProcessTask(ZkZxsjfx fx, List<String> dms, Map<String, String> bizParams) {
this.fx = fx;
this.dms = dms;
this.bizParams = bizParams;
}
@Override
public void run() {
// 要执行的业务
}
}
注意事项
scheduledExecutorService.schedule(new TriggerProcessTask(fx, dms, taskParams), 30000, TimeUnit.MILLISECONDS);
线程池往往处理的是多个任务,参数fx, dms, taskParams一定是每个任务一个对象,不要一个对象给赋值给很多任务。
举例:taskParams是一个map,那么每new TriggerProcessTask一次,就需要重新赋值一个新的map对象。否则会出现多个线程访问同一个变量,也就是变量共享了,这样就会导致线程执行的时候参数往往都是取的最新值。
一般做法:
for(...){
List<String> taskZbdms = new ArrayList<>();
taskZbdms.add(...);
Map<String, String> taskParams = new HashMap<>();
taskParams.put(...);
scheduledExecutorService.schedule(new TriggerProcessTask(fz, zbdms, taskParams), 30000, TimeUnit.MILLISECONDS);
}