使用ScheduledExecutorService启动多个任务,并在运行时删除任务

时间:2013-07-09 02:17:57

标签: java multithreading

这是我的代码结构的样子

 Class TaskA implements runnable {

    void run() {
      if(not leader node) {
          exit this task;
          (never run it again)
         }

       //do stuff
    } 
  };

同样

    Class TaskB implements runnable { ....
    Class TaskC implements runnable { ....


 class Scheduler {
    TaskA memberTaskA;
    TaskB memberTaskB;
    TaskC memberTaskC;
    private ScheduledExecutorService executor;
    private ScheduledFuture futureA, futureB, futureC;

    public Scheduler(TaskA a, TaskB b, TaskC c) {
    memberTaskA = a;
    memberTaskB = b;
    memberTaskC = c;
    }

    public void start() {

    exectuor = Executors.newSingleThreadScheduledExecutor();

    futureA = scheduleWithFixedDelay(memberTaskA, 
                           6000,
                           6000,
                           TimeUnit.MILLISECONDS);
    futureB = scheduleWithFixedDelay(memberTaskB, 
                           6000,
                           6000,
                           TimeUnit.MILLISECONDS);
    futureC = scheduleWithFixedDelay(memberTaskC, 
                           6000,
                           6000,
                           TimeUnit.MILLISECONDS);


    }

};

如果在任务的run()方法中满足“不是领导节点”条件,我需要能够不再安排任务。 一种可能的方法是为每个Task创建一个单独的stop方法,如stopTaskA(),stopTaskB()和stopTaskC()。将Scheduler类的对象传递给每个Task并显式调用相应的stopTask()方法。 例如:

stopTaskA(){
futureA.cancel(false);
}

这看起来不是一个非常优雅的解决方案。

任何有关更好设计的想法?

1 个答案:

答案 0 :(得分:0)

如何使您的任务实现Callable而不是Runnable。如果他们应该继续运行,则返回true,否则实际上不负责取消自己(关注点的良好分离)。

class TaskCallable implements Callable<Boolean> {

    /** Returns true if it should continue to be scheduled, false otherwise */
    @Override
    public Boolean call() throws Exception {
        if (random.nextDouble() < .1) {
            System.out.println("FINISHED");
            return false;
        }
        System.out.println("working...");
        return true;
    }
}   

引用/保持类,你上面的“Scheduler”可能看起来像这样(我把它写成了convieneince的单元测试):

private ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

@Test
public void test() throws ExecutionException, InterruptedException {

    TaskCallable task1 = new TaskCallable();
    TaskCallable task2 = new TaskCallable();
    TaskCallable task3 = new TaskCallable();

    ScheduledFuture<Boolean> future1 = executor.schedule(task1, 100, MICROSECONDS);
    ScheduledFuture<Boolean> future2 = executor.schedule(task2, 100, MICROSECONDS);
    ScheduledFuture<Boolean> future3 = executor.schedule(task3, 100, MICROSECONDS);

    while (future1 != null || future2 != null || future3 != null) {
        future1 = reScheduleIfNecessary(future1, task1);
        future2 = reScheduleIfNecessary(future2, task2);
        future3 = reScheduleIfNecessary(future3, task3);
    }

}

其中

/**
 * Return NULL if the specified future returns FALSE (indicating it is finished). If the specified future returns
 * true then the task is re-scheduled and a new FUTURE is returned.  To facilitate polling this method will return
 * the passed future if it does not answer in 10 ms.
 */
private ScheduledFuture<Boolean> reScheduleIfNecessary(ScheduledFuture<Boolean> scheduledFuture,
                                                       TaskCallable task) throws ExecutionException, InterruptedException {
    if (scheduledFuture != null) {
        try {
            if (scheduledFuture.get(10, TimeUnit.MILLISECONDS)) {
                return executor.schedule(task, 100, MICROSECONDS);
            }
        } catch (TimeoutException e) {
            return scheduledFuture;
        }
    }
    return null;
}

您正在重新安排自己,而不是让ScheduledExecutorService为您执行此操作 - 但也许更好地反映了您的意图 - 只有在某些条件为真时再次运行。

您可以轻松地将此概括为N个任务。