首先创建执行程序。
你有几种可能性。
如果我想,你的任务实现一个简单的界面来查询(像“NeedReschedule”或“已完成”的枚举的东西)自己的状态,然后实现(实现Runnable
)为您的任务的包装,其将采取的任务,执行者作为instanciation参数。这个包装器将运行它所绑定的任务,之后检查它的状态,并且如果需要的话在终止之前在执行器中重新调度它自己的一个副本。
或者,您可以使用执行机制来指示该任务必须重新计划的包装器。 这个解决方案更简单一些,因为它不需要特定的接口来完成任务,所以简单的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());
}
}
你也可以有一个专门的线程来监视其他线程的结果(使用消息队列),如果需要重新安排,但你失去了一个线程,相比于其他的解决方案。
只需创建一个等于当前值的新任务并将其放入队列。完成当前任务 – hoaz
@hoaz:您的意思是从任务内部引用执行程序? – Cratylus
@Cratylus - 是的,如果任务有一个引用回执行者,它可以重新排队。只要确保执行程序的待处理任务队列是无限的,或者您可以最终锁定自己。 – jtahlborn