有没有办法将任务放回执行程序队列中

时间:2012-11-20 20:54:53

标签: java multithreading concurrency executorservice executors

我有一系列任务(即Runnable s)由Executor执行。
每个任务都要求某个条件有效才能继续。我有兴趣知道是否有办法以某种方式配置Executor在队列末尾移动任务,并在条件有效且任务能够执行和完成时尝试执行它们。
所以行为就像:

  1. Thread-1从队列中获取任务,run称为
  2. 内部run条件尚未生效
  3. 任务停止,Thread-1将任务放在队列的末尾 获得下一个执行任务
  4. 稍后Thread-X(来自线程池)从队列条件再次选择任务是有效的 正在执行任务

3 个答案:

答案 0 :(得分:3)

首先创建执行程序。

你有几个可能性。

如果我认为你的任务实现了一个简单的界面来查询它们的状态(类似于'NeedReschedule'或'Completed'的枚举),那么为你的任务实现一个包装器(实现Runnable)任务和执行者作为实例参数。这个包装器将运行它绑定的任务,之后检查它的状态,如果需要,在终止之前在执行程序中重新安排自己的副本。

或者,您可以使用execption机制向包装器发出必须重新调度任务的信号。 这个解决方案更简单,因为它不需要特定的接口来完成任务,因此简单的Runnable可以毫无困难地抛出系统。但是,异常会导致更多的计算时间(对象构造,堆栈跟踪等)。

这是使用异常信令机制的包装器的可能实现。 您需要实现扩展RescheduleException的{​​{1}}类,它可能被包装的runnable触发(在此设置中不需要更具体的任务接口)。您也可以使用另一个答案中提出的简单Throwable,但您必须测试消息字符串以了解这是否是您正在等待的异常。

RuntimeException

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

 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);
    }
}

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

答案 1 :(得分:3)

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

答案 2 :(得分: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);