首先创建执行器。
你有几个可能性。
如果我假设您的任务实现了一个简单的接口来查询它们的状态(类似于带有“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());
}
}
您还可以有一个专用线程来监视其他线程的结果(使用消息队列)并在必要时重新安排,但与其他解决方案相比,您会丢失一个线程。