Сначала создайте исполнителя.
У вас есть несколько возможностей.
Если я предполагаю, что ваши задачи реализуют простой интерфейс для запроса их статуса (что-то вроде перечисления с «NeedReschedule» или «Completed»), тогда реализуйте оболочку (реализующую Runnable
) для ваших задач, которая будет принимать задачу и исполнителя в качестве экземпляра параметры. Эта оболочка запустит задачу, к которой она привязана, затем проверит ее статус и, если необходимо, перепланирует свою копию в исполнителе перед завершением.
В качестве альтернативы вы можете использовать механизм выполнения, чтобы сообщить оболочке, что задача должна быть перепланирована. Это решение проще в том смысле, что оно не требует определенного интерфейса для вашей задачи, так что простой 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());
}
}
У вас также может быть выделенный поток для отслеживания результатов других потоков (с использованием очереди сообщений) и перепланирования при необходимости, но вы теряете один поток по сравнению с другим решением.
person
didierc
schedule
20.11.2012