7

我有一系列任务(即Runnables)要由Executor.
每个任务都需要一定的条件才能继续进行。我很想知道是否有办法以某种方式配置Executor以在队列末尾移动任务,并在条件有效并且任务能够执行和完成时尝试稍后执行它们。
所以行为类似于:

  1. Thread-1从队列中获取任务run并被调用
  2. 内部run条件尚未生效
  3. 任务停止并将Thread-1任务放在队列末尾并获取下一个要执行的任务
  4. 稍后Thread-X(从线程池)再次从队列中选择任务条件有效并且正在执行任务
4

3 回答 3

3

首先创建执行器。

你有几个可能性。

如果我假设您的任务实现了一个简单的接口来查询它们的状态(类似于带有“NeedReschedule”或“Completed”的枚举),那么Runnable为您的任务实现一个包装器(实现),它将任务和执行器作为实例化参数. 这个包装器将运行它所绑定的任务,然后检查它的状态,如果有必要,在终止之前在执行器中重新安排它自己的副本。

或者,您可以使用 execption 机制向包装器发出必须重新安排任务的信号。这个解决方案更简单,因为它不需要为您的任务提供特定的界面,因此Runnable可以毫无问题地在系统中投入简单。但是,异常会产生更多的计算时间(对象构造、堆栈跟踪等)。

这是使用异常信号机制的包装器的可能实现。您需要实现RescheduleException类扩展Throwable,它可能由包装的可运行文件触发(此设置中的任务不需要更具体的接口)。您也可以使用RuntimeException另一个答案中建议的简单方法,但您必须测试消息字符串以了解这是否是您正在等待的异常。

 public class TaskWrapper implements Runnable {

    private final ExecutorService executor;
    private final Runnable task;       

    public TaskWrapper(ExecutorService e, Runnable t){
         executor = e;
         task = t;
    }

@Override
public void run() {

    try {
               task.run();
    } 
    catch (RescheduleException e) {
        executor.execute(this);
    }
}

这是一个非常简单的应用程序,随机启动 200 个包装任务,要求重新安排。

class Task implements Runnable {

  @Override
  public void run(){
     if (Maths.random() > 0.5)
      throw new RescheduleException();
   }     
}


public class Main {

public static void main(String[] args){

    ExecutorService executor = Executors.newFixedThreadPool(10);

    int i = 200;
            while(i--)
       executor.execute(new TaskWrapper(executor, new Task());
}
}

您还可以有一个专用线程来监视其他线程的结果(使用消息队列)并在必要时重新安排,但与其他解决方案相比,您会丢失一个线程。

于 2012-11-20T21:24:17.297 回答
3

在 Java 6 中,ThreadPoolExecutor构造函数采用 a BlockingQueue<Runnable>,用于存储排队的任务。您可以实现这样一个阻塞队列,它会覆盖,poll()以便如果尝试删除并执行“就绪”作业,则poll可以正常进行。否则,runnable 将放在队列的后面,您可能会在短暂的超时后再次尝试轮询。

于 2012-11-20T21:24:38.417 回答
3

除非您必须忙于等待,否则您可以使用适当的轮询间隔将重复任务添加到 ScheduledExecutorService,您可以在“有效”运行后取消或终止该轮询间隔。

ScheduleExecutorService ses = ...

ses.scheduleAtFixedRate(new Runnable() {
    public void run() {
        if (!isValid()) return;
        preformTask();
        throw new RuntimeException("Last run");
    }
}, PERIOD, PERIOD, TimeUnit.MILLI_SECONDS);
于 2012-11-20T21:41:42.807 回答