我的任务包含一些标识符。我需要ScheduledExecutionService,它将在指定的时间间隔后执行给定的任务(如所有标准实现所做的那样),但有一个限制:它不能启动任务,直到具有相同标识符的上一个任务完成(当然,其他任务必须执行)同时地)。
换句话说,对于给定的ID,所有任务必须连续执行。
是否准备好在标准或第三方库中使用实现或以简单的方式实现它?
同样返回ScheduledFuture.cancel必须正常工作,因为当前执行的任务可能会取消计划任务。
答案 0 :(得分:1)
这是我如何做到这一点的大致想法。 (未经测试)
public class Solution {
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1000);
//a map of taskQueues. We queue all tasks of same ID.
private static final ConcurrentHashMap<Long, BlockingDeque<MyTask>> mapOfTasks = new ConcurrentHashMap<>(1000);
public boolean submitWithChecks(Runnable task, long ID, long interval) {
final BlockingDeque<MyTask> queue;
if(mapOfTasks.containsKey(ID)) queue = mapOfTasks.get(ID);
else queue = new LinkedBlockingDeque<>(1000);
//At this point we have a valid queue object
try {
//insert the task into the queue
queue.putLast(new MyTask(task, ID, interval));
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
//If the queue was already present it will get Updated my previous queue.putLast operation
//If the queue was not present, we put it in the map and start a new queueEater thread.
if(!mapOfTasks.containsKey(ID)) {
mapOfTasks.put(ID, queue);
scheduler.submit(new QueueEater(ID)); //start a new task execution queue
}
return true;
}
private class QueueEater implements Runnable {
//This queueEater will consume the queue with this taskID
private final Long ID;
private QueueEater(Long id) {
ID = id;
}
@Override
public void run() {
//QueueEater will poll the mapOfTasks for the queue Object with its associated ID
while (mapOfTasks.containsKey(ID)) {
final BlockingDeque<MyTask> tasks = mapOfTasks.get(ID);
if(tasks.size() == 0) {
mapOfTasks.remove(ID);
return; //if task queue empty kill this thread;
}
final MyTask myTask;
try {
myTask = tasks.takeFirst();
//schedule the task with given interval
final Future future = scheduler.schedule(myTask.getTask(), myTask.getInterval(), TimeUnit.SECONDS);
future.get(); //wait till this task gets executed before scheduling new task
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
private class MyTask {
private final Runnable task;
private final long ID;
private final long interval;
public long getInterval() {
return interval;
}
public long getID() {
return ID;
}
public Runnable getTask() {
return task;
}
private MyTask(Runnable task, long id, long interval) {
this.task = task;
ID = id;
this.interval = interval;
}
}
}