开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情
一、任务
public interface ExecuteTask{
/**
* 是否应该执行任务
* @return
*/
boolean shouldProcess();
}
1.1 延时任务
1.执行时间
延时任务会判断当前执行时间 - 最后一次执行时间是否大于任务时间间隔来判断是否需要执行
2.合并任务
如果任务队列中出现相同任务,需要进行合并
3.多次重试
执行失败,可以重试
public abstract class AbstractDelayTask implements ExecuteTask {
/**
* 任务间隔
*/
private long taskInterval;
/**
* 最后一次执行时间
*/
private long lastProcessTime;
/**
* 重试次数
*/
private AtomicInteger retryTimes = new AtomicInteger(0);
public AbstractDelayTask(long taskInterval) {
this.taskInterval = taskInterval;
this.lastProcessTime = System.currentTimeMillis();
}
public AbstractDelayTask(long taskInterval, long lastProcessTime) {
this.taskInterval = taskInterval;
this.lastProcessTime = lastProcessTime;
}
/**
* 合并任务
* @param task
*/
public abstract void merge(AbstractDelayTask task);
@Override
public boolean shouldProcess() {
return (System.currentTimeMillis() - this.lastProcessTime >= this.taskInterval);
}
public long getTaskInterval() {
return taskInterval;
}
public void setTaskInterval(long taskInterval) {
this.taskInterval = taskInterval;
}
public long getLastProcessTime() {
return lastProcessTime;
}
public void setLastProcessTime(long lastProcessTime) {
this.lastProcessTime = lastProcessTime;
}
public int getRetryTimes() {
return retryTimes.get();
}
public void increment() {
retryTimes.incrementAndGet();
}
}
1.2 执行任务
执行任务实现了Runnable接口
public abstract class AbstractExecuteTask implements ExecuteTask,Runnable {
@Override
public boolean shouldProcess() {
return true;
}
}
二、执行器
对执行任务做处理的,可以按照不同的执行任务实现不同的执行器
public interface TaskProcessor<T extends ExecuteTask> {
/**
* 执行任务
*
* @param task
* @return
*/
boolean process(T task);
}
三、执行引擎
执行任务由执行引擎进行处理,将不同的执行任务分派给不同的执行引擎进行执行
public interface TaskExecuteEngine <T extends ExecuteTask> extends Closeable {
/**
* 添加任务
* @param key
* @param task
*/
void addTask(Object key, T task);
/**
* 移除任务
* @param key
* @return
*/
T removeTask(Object key);
/**
* 获取执行器
* @param key
* @return
*/
TaskProcessor getProcessor(Object key);
/**
* 添加执行器
* @param key
* @param taskProcessor
*/
void addProcessor(Object key, TaskProcessor taskProcessor);
/**
* 移除执行器
* @param key
*/
void removeProcessor(Object key);
/**
* 设置默认执行器
* @param defaultTaskProcessor
*/
void setDefaultTaskProcessor(TaskProcessor defaultTaskProcessor);
/**
* 获取所有任务key
* @return
*/
Collection<Object> getAllTaskKeys();
}
执行器引擎维护了对执行器的所有操作
public abstract class AbstractTaskExecuteEngine<T extends ExecuteTask> implements TaskExecuteEngine<T> {
private final ConcurrentHashMap<Object, TaskProcessor> taskProcessors = new ConcurrentHashMap();
private TaskProcessor defaultTaskProcessor;
protected final Logger log;
public AbstractTaskExecuteEngine(Logger logger) {
this.log = null != logger ? logger : LogProvider.getLogger(AbstractTaskExecuteEngine.class);
}
@Override
public TaskProcessor getProcessor(Object key) {
return taskProcessors.containsKey(key) ? taskProcessors.get(key) : defaultTaskProcessor;
}
@Override
public void addProcessor(Object key, TaskProcessor taskProcessor) {
//如果不存在则放入执行器
taskProcessors.putIfAbsent(key, taskProcessor);
}
@Override
public void removeProcessor(Object key) {
taskProcessors.remove(key);
}
@Override
public void setDefaultTaskProcessor(TaskProcessor defaultTaskProcessor) {
this.defaultTaskProcessor = defaultTaskProcessor;
}
}
3.1延时任务执行引擎
3.1.1待执行任务列表
延时任务执行引擎中会将任务添加至延时任务列表中
3.1.2定时任务处理器
定时任务处理器按一定时间从延时任务列表中获取任务,然后匹配指定的处理器进行处理
3.1.3任务重试
如果定时任务处理失败,会按任务的重试次数重新放回任务队列重新执行
public class DelayTaskExecuteEngine extends AbstractTaskExecuteEngine<AbstractDelayTask> {
protected final ConcurrentHashMap<Object, AbstractDelayTask> tasks;
protected final ScheduledExecutorService processingExecutor;
protected final ReentrantLock lock = new ReentrantLock();
private int maxRetryTimes = 0;
public DelayTaskExecuteEngine(String name) {
this(name, 32, LogProvider.getLogger(DelayTaskExecuteEngine.class), 100L, 3);
}
public DelayTaskExecuteEngine(String name, Logger logger) {
this(name, 32, logger, 100L, 3);
}
public DelayTaskExecuteEngine(String name, int initCapacity, Logger logger) {
this(name, initCapacity, logger, 100L, 3);
}
public DelayTaskExecuteEngine(String name, int initCapacity, Logger logger, long processInterval) {
this(name, initCapacity, logger, processInterval, 3);
}
public DelayTaskExecuteEngine(String name, int initCapacity, Logger logger, long processInterval, int maxRetryTimes) {
super(logger);
this.maxRetryTimes = maxRetryTimes;
tasks = new ConcurrentHashMap<Object, AbstractDelayTask>(initCapacity);
this.processingExecutor = Executors.newScheduledThreadPool(1, new NameThreadFactory(name));
//延时定时任务
processingExecutor
.scheduleWithFixedDelay(new DelayProcessRunnable(), processInterval, processInterval, TimeUnit.MILLISECONDS);
}
@Override
public void shutdown() throws CommonException {
processingExecutor.shutdown();
}
@Override
public void addTask(Object key, AbstractDelayTask newTask) {
AbstractDelayTask existTask = tasks.get(key);
lock.lock();
try {
if (null != existTask) {
newTask.merge(existTask);
}
tasks.put(key, newTask);
} finally {
lock.unlock();
}
}
@Override
public AbstractDelayTask removeTask(Object key) {
AbstractDelayTask existTask = tasks.get(key);
lock.lock();
try {
if (null != existTask) {
return tasks.remove(key);
}
return null;
} finally {
lock.unlock();
}
}
@Override
public Collection<Object> getAllTaskKeys() {
Collection<Object> keys = new HashSet<Object>();
lock.lock();
try {
keys.addAll(tasks.keySet());
} finally {
lock.unlock();
}
return keys;
}
protected void processTasks() {
Collection<Object> keys = getAllTaskKeys();
for (Object taskKey : keys) {
AbstractDelayTask task = removeTask(taskKey);
if (null == task || !task.shouldProcess()) {
continue;
}
TaskProcessor processor = getProcessor(taskKey);
if (processor == null) {
continue;
}
try {
// 执行当前任务
if (!processor.process(task)) {
//执行失败再次执行
retryFailedTask(taskKey, task);
}
} catch (Throwable e) {
log.error("task execute error : " + e.toString(), e);
//执行失败再次执行
retryFailedTask(taskKey, task);
}
}
}
private void retryFailedTask(Object key, AbstractDelayTask task) {
if (task.getRetryTimes() >= this.maxRetryTimes) {
return;
}
task.increment();
task.setLastProcessTime(System.currentTimeMillis());
addTask(key, task);
}
private class DelayProcessRunnable extends ExecuteRunnable {
@Override
protected void executeBody() {
processTasks();
}
}
}
3.2任务执行引擎
3.2.1 工作执行器
任务执行引擎中会会维护工作执行器,当任务没有匹配到执行器的时候由工作执行器执行任务
public class ExecuteTaskExecuteEngine extends AbstractTaskExecuteEngine<AbstractExecuteTask> {
private final TaskExecuteWorker[] executeWorkers;
public ExecuteTaskExecuteEngine(String name) {
this(name, LogProvider.getLogger(ExecuteTaskExecuteEngine.class), ThreadUtil.getSuitableThreadCount(1));
}
public ExecuteTaskExecuteEngine(String name, Logger logger) {
this(name, logger, ThreadUtil.getSuitableThreadCount(1));
}
public ExecuteTaskExecuteEngine(String name, Logger logger, int dispatchWorkerCount) {
super(logger);
executeWorkers = new TaskExecuteWorker[dispatchWorkerCount];
for (int mod = 0; mod < dispatchWorkerCount; ++mod) {
executeWorkers[mod] = new TaskExecuteWorker(name, mod, dispatchWorkerCount, this.log);
}
}
@Override
public void addTask(Object key, AbstractExecuteTask task) {
TaskProcessor processor = getProcessor(key);
if (null != processor) {
processor.process(task);
return;
}
TaskExecuteWorker worker = getWorker(key);
worker.process(task);
}
@Override
public AbstractExecuteTask removeTask(Object key) {
log.warn("ExecuteTaskEngine do not support remove task");
return null;
}
@Override
public Collection<Object> getAllTaskKeys() {
log.warn("ExecuteTaskEngine do not support get all task keys");
return null;
}
@Override
public void shutdown() throws CommonException {
for (TaskExecuteWorker each : executeWorkers) {
each.shutdown();
}
}
/**
* 获取工作线程的状态
*
* @return
*/
public String workersStatus() {
StringBuilder sb = new StringBuilder();
for (TaskExecuteWorker worker : executeWorkers) {
sb.append(worker.status()).append("\n");
}
return sb.toString();
}
private TaskExecuteWorker getWorker(Object tag) {
int idx = (tag.hashCode() & Integer.MAX_VALUE) % workersCount();
return executeWorkers[idx];
}
private int workersCount() {
return executeWorkers.length;
}
}
工作执行器
public final class TaskExecuteWorker implements TaskProcessor<ExecuteTask>, Closeable {
/**
* Max task queue size 32768.
*/
private static final int QUEUE_CAPACITY = 1 << 15;
private final Logger log;
private final String name;
private final BlockingQueue<Runnable> queue;
private final AtomicBoolean closed;
public TaskExecuteWorker(final String name, final int mod, final int total) {
this(name, mod, total, null);
}
public TaskExecuteWorker(final String name, final int mod, final int total, final Logger logger) {
this.name = name + "_" + mod + "%" + total;
this.queue = new ArrayBlockingQueue<Runnable>(QUEUE_CAPACITY);
this.closed = new AtomicBoolean(false);
this.log = null == logger ? LogProvider.getLogger(TaskExecuteWorker.class) : logger;
new InnerWorker(name).start();
}
public String getName() {
return name;
}
@Override
public boolean process(ExecuteTask task) {
try {
queue.put((Runnable) task);
} catch (InterruptedException ire) {
log.error(ire.toString(), ire);
return false;
}
return true;
}
public int pendingTaskCount() {
return queue.size();
}
/**
* Worker status.
*/
public String status() {
return name + ", pending tasks: " + pendingTaskCount();
}
@Override
public void shutdown() throws CommonException {
queue.clear();
closed.compareAndSet(false, true);
}
/**
* Inner execute worker.
*/
private class InnerWorker extends Thread {
InnerWorker(String name) {
setDaemon(false);
setName(name);
}
@Override
public void run() {
while (!closed.get()) {
try {
Runnable task = queue.take();
long begin = System.currentTimeMillis();
task.run();
long duration = System.currentTimeMillis() - begin;
if (duration > 1000L) {
log.warn("distro task {} takes {}ms", task, duration);
}
} catch (Throwable e) {
log.error("[DISTRO-FAILED] " + e.toString(), e);
}
}
}
}
}
四、测试
4.1 延时工作引擎测试
public class DelayTaskExecuteEngineTest {
private DelayTaskExecuteEngine executeEngine;
@Before
public void build() {
executeEngine = new DelayTaskExecuteEngine("TEST");
executeEngine.setDefaultTaskProcessor(new TestDelayProcessor());
}
@Test
public void testAddTask() throws InterruptedException {
String taskKey = "5000";
executeEngine.addTask(taskKey, new TestDelayTask(1000, System.currentTimeMillis()));
TimeUnit.SECONDS.sleep(200);
}
class TestDelayProcessor implements TaskProcessor {
@Override
public boolean process(ExecuteTask task) {
Calendar now = Calendar.getInstance();
System.out.println(now.getTime() + "== 进入TestDelay");
return false;
}
}
class TestDelayTask extends AbstractDelayTask {
public TestDelayTask(long taskInterval, long lastProcessTime) {
super(taskInterval, lastProcessTime);
}
@Override
public void merge(AbstractDelayTask task) {
Calendar now = Calendar.getInstance();
System.out.println(now.getTime() + "== 进入merge");
}
}
}
4.1 工作引擎测试
ublic class ExecuteTaskExecuteEngineTest {
private ExecuteTaskExecuteEngine executeEngine;
@Before
public void build() {
executeEngine = new ExecuteTaskExecuteEngine("Execute");
}
@Test
public void testAddTask() {
for (int i = 0; i < 20; i++) {
executeEngine.addTask(i, new TestDelayTask());
}
}
class TestDelayTask extends AbstractExecuteTask {
@Override
public void run() {
Calendar now = Calendar.getInstance();
System.out.println(now.getTime() + "== 进入TestDelayTask");
}
}
}