我有一系列任务(即Runnable
s)由Executor
执行。
每个任务都要求某个条件有效才能继续。我有兴趣知道是否有办法以某种方式配置Executor
在队列末尾移动任务,并在条件有效且任务能够执行和完成时尝试执行它们。
所以行为就像:
Thread-1
从队列中获取任务,run
称为run
条件尚未生效Thread-1
将任务放在队列的末尾
获得下一个执行任务Thread-X
(来自线程池)从队列条件再次选择任务是有效的
正在执行任务答案 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);