Java установила обратный вызов из ExecutorService
У меня есть fixedThreadPool, который я использую для запуска кучки рабочих потоков для параллельного выполнения задачи со многими компонентами.
Когда все потоки закончены, я получаю их результаты (которые довольно большие) с помощью метода (getResult) и записывают их в файл.
В конечном счете, чтобы сохранить память и увидеть промежуточные результаты, я хотел бы, чтобы каждый поток записывал свой результат в файл, как только он заканчивает выполнение, а затем освобождает свою память.
Как правило, я бы добавил код к этому эффекту до конца метода run(). Однако некоторые другие объекты этого класса также вызывают эти потоки, но НЕ хотят, чтобы они записывали свои результаты в файл - вместо этого они используют свои результаты для выполнения других вычислений, которые в конечном итоге записываются в файл.
Итак, мне было интересно, можно ли подключить функцию обратного вызова к событию завершения потока с помощью ExecutorService. Таким образом, я могу сразу получить его результат и освободить память в этом сценарии, но не нарушать код, когда эти потоки используются в других сценариях.
Возможно ли это?
Ответы
Ответ 1
ExecutorService#submit
return FutureTask<T>
, который помогает вы получите результат, а метод ExecutorService#get
заблокирует выполнение до тех пор, пока вычисление не будет завершено. Пример -
ExecutorService executor = Executors.newFixedThreadPool(10);
Future<Long> future = executor.submit(new Callable<Long>(){
@Override
public Long call() throws Exception {
long sum = 0;
for (long i = 0; i <= 10000000l; i++) {
sum += i;
}
return sum;
}
});
Long result = future.get();
System.out.println(result);
Ответ 2
Если вы используете Google Guava, вы можете использовать интерфейс ListenableFuture следующим образом:
- Преобразовать
ExecutorService
в ListeningExecutorService через MoreExecutors.listeningDecorator(existingExecutorService)
- Метод
submit(Callable<V>)
в ListeningExecutorService
был сужен, чтобы вернуть ListenableFuture
, который является подынтерфейсом Future
.
ListenableFuture
имеет метод addListener()
, так что вы можете зарегистрировать обратный вызов для запуска, когда будущее будет завершено.
Ответ 3
Итак, мне было интересно, можно ли подключить функцию обратного вызова к событию завершения потока с помощью ExecutorService.
Не прямо, нет, но есть несколько способов, которыми вы могли бы это сделать. Самый простой способ, который приходит на ум, - обернуть ваш Runnable
в другой Runnable
, который будет собирать результаты.
Итак, вы сделали бы что-то вроде:
threadPool.submit(new ResultPrinter(myRunnable));
...
private static class ResultPrinter implements Runnable {
private final MyRunnable myRunnable;
public ResultPrinter(MyRunnable myRunnable) {
this.myRunnable = myRunnable;
}
public void run() {
myRunnable.run();
Results results = myRunnable.getResults();
// print results;
}
}
Ответ 4
Вы можете добавить обратный вызов для случая, когда поток возвращается в Java 8+ с использованием CompletableFuture
, как показано ниже, где t
- результат ваших длительных вычислений,
CompletableFuture.supplyAsync(() -> {
T t = new T();
// do something
return t;
}).thenApply(t -> {
// process t
});
Если вы хотите использовать обратные вызовы только в Java 7, вы можете сделать что-то вроде
int x = 10;
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(x);
Future<T> result = fixedThreadPool.submit(() -> {
// do calculation
return T;
});
fixedThreadPool.submit(() -> {
long minutesToWait = 5;
T t = null;
try {
t = result.get(minutesToWait, TimeUnit.MINUTES);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
LOGGER.error(e);
}
if (t != null) {
// process t
}
});
Ответ 5
Не удалось найти ответ на StackOverflow:
Обратный вызов Java ExecutorService при завершении потока
Спасибо за терпение!