2014-12-03 28 views
2

我的任務包含一些標識符。我需要ScheduledExecutionService,它將在指定的時間間隔後執行給定的任務(如所有標準實現一樣),但有一個限制:它必須不啓動任務,直到具有相同標識符的前一個任務完成(當然,其他任務必須執行兼)。具有部分任務排序的ScheduledExecutorService

換句話說,對於給定的ID,所有任務必須連續執行。

是否準備好在標準或第三方庫中使用實現或簡單的方法來實現它?

也返回ScheduledFuture.cancel必須正常工作,因爲計劃的任務可能會被當前執行的任務取消。

回答

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; 
     } 
    } 
} 
+1

我做了類似的解決方案。 https://gist.github.com/vbezhenar/cc49928995c03c1289bb這是代碼。 – vbezhenar 2014-12-04 12:22:58

相關問題