具有部分任务排序的ScheduledExecutorService

时间:2014-12-03 12:59:12

标签: java concurrency scheduler

我的任务包含一些标识符。我需要ScheduledExecutionService,它将在指定的时间间隔后执行给定的任务(如所有标准实现所做的那样),但有一个限制:它不能启动任务,直到具有相同标识符的上一个任务完成(当然,其他任务必须执行)同时地)。

换句话说,对于给定的ID,所有任务必须连续执行。

是否准备好在标准或第三方库中使用实现或以简单的方式实现它?

同样返回ScheduledFuture.cancel必须正常工作,因为当前执行的任务可能会取消计划任务。

1 个答案:

答案 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;
        }
    }
}