场景:多个任务提交到redis的list中,多机器部署,每台机器都是在启动项目的时候启动这个从redis的list中pop任务进行处理,如果redis的list中等待timeout=2s没有数据就会再次去list中去取task;任务处理比较耗时,大概将近60s处理完毕
- 基于redis的分布式任务提交处理的线程池
public abstract class AbstractDistributedTaskHandler extends ThreadPoolExecutor {
private final Logger logger = LoggerFactory.getLogger(getClass());
//根据自己的redis进行相应的调整
private ListCommands listCommands;
private HashCommands hashCommands;
private boolean running;
private final HashMap<Integer, ProjectFutureTask> tasks = new HashMap<>(100);
private TimeUnit taskTimeoutTimeUnit = TimeUnit.MINUTES;
private long taskTimeout = 30;
public AbstractDistributedTaskHandler() {
this(5, "task");
}
/**
* 构造当前节点线程池
*
* @param poolSize 用于提交用户的线程池大小,另外增加2个内部线程用于提交和检测超时
*/
public AbstractDistributedTaskHandler(int poolSize, String poolThreadName) {
super(poolSize + 2, poolSize + 2, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100), new NamedThreadFactory(poolThreadName), new AbortPolicy());
}
/**
* 初始化方法
*/
public final void init() {
listCommands = RedisFactory.getClusterListCommands(getRedisGroupName());
hashCommands = RedisFactory.getClusterHashCommands(getRedisGroupName());
}
/**
* 开始启动接收分布式线程
*
* @param taskTimeoutTimeUnit 每个线程超时时间单位
* @param taskTimeout 每个线程超时时间
*/
public final void start(TimeUnit taskTimeoutTimeUnit, long taskTimeout) {
this.taskTimeoutTimeUnit = taskTimeoutTimeUnit;
this.taskTimeout = taskTimeout;
this.running = true;
execute(() -> fetchNewTask());
execute(() -> checkTaskTimeout());
}
@Override
public void shutdown() {
running = false;
super.shutdown();
}
/**
* 开始从redis获取任务并提交到线程池
*/
private void fetchNewTask() {
while (running) {
if (getActiveCount() >= getCorePoolSize()) {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
continue;
}
Task task = listCommands.rightPop(getRedisNamespace(), getTaskQueueRedisKey(), 2, TimeUnit.SECONDS, true);
if (task != null) {
ProjectFutureTask future = new ProjectFutureTask(task);
execute(future);
tasks.put(task.getTaskId(), future);
}
}
}
/**
* 开始线程池中的线程超时检查
*/
private void checkTaskTimeout() {
while (running) {
Iterator<Map.Entry<Integer, ProjectFutureTask>> it = tasks.entrySet().iterator();
while (it.hasNext()) {
ProjectFutureTask futureTask = it.next().getValue();
if (futureTask.isDone() || futureTask.isCancelled()) {
it.remove();
} else if (System.currentTimeMillis() - futureTask