ExecutorService.submit() не возвращается после отправки задачи
Я хочу сделать асинхронный вызов функции и вернуться, не дожидаясь результата (в Java). Код, который я написал для того же:
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(new Callable<Void>()
{
public Void call() throws Exception, TimeoutException {
hostNetworkSystem.updatePortGroup("Management Network", spec);
return null;
}
});
Я пробовал и Runnable, и Callable, но когда я отлаживаю код в Eclipse, поток застревает в функции call(), которая не возвращается сразу после отправки задачи.
Я что-то здесь упускаю?
Это застревает в:
hostNetworkSystem.updatePortGroup("Management Network", spec);
точнее. Действие выполняется, как я вижу результаты, но оно не возвращается отсюда.
Для лучшего понимания вот как выглядит весь вызов:
public void main()
{
try {
AsyncCall asyncCalls = new AsyncCall();
List<PortGroupData> portData = asyncCalls.updatePortGroupFuture(hostNetworkSystem, portGroupName,
portGroupData, modelType, oobmStatus, vlanID);
return portData;
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("InterruptedException " + e.getMessage().toString());
} catch (ExecutionException e) {
System.out.println("ExecutionException " + e.getMessage().toString());
e.printStackTrace();
} catch (Exception e) {
System.out.println("Exception " + e.getMessage().toString());
e.printStackTrace();
}
}
public void updatePortGroupFuture(final HostNetworkSystem hostNetworkSystem,
final String portGroupName, final NetworkParameters networkData, final String modelType,
final boolean oobmStatus, int vlanID) throws InterruptedException, ExecutionException, Exception
{
<some other actions>
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(new Callable<Void>()
{
public Void call() throws Exception, TimeoutException {
hostNetworkSystem.updatePortGroup("Management Network", spec);
return null;
}
});
return;
}
3 ответа
Измените свой код как
Future<Void> future = executorService.submit(new Callable<Void>()
{
public Void call() throws Exception, TimeoutException {
System.out.println("before call");
hostNetworkSystem.updatePortGroup("Management Network", spec);
System.out.println("after call");
return null;
}
});
try{
result = future.get(5000, TimeUnit.MILLISECONDS);
}catch(TimeoutException e){
System.out.println("Time out after 5 seconds");
futureResult.cancel(true);
}catch(InterruptedException ie){
System.out.println("Error: Interrupted");
}catch(ExecutionException ee){
System.out.println("Error: Execution interrupted");
}
Если вы получаете
TimeoutException
измените значение времени ожидания на какое-то большое число. Проверьте до и после выписки. Если вы получили до вызова и не получили после вызова, это означает, что произошло какое-то исключение.Чтобы узнать исключение, измените
submit()
вexecute()
и поймать исключение.
submit()
глотает исключения. Посмотрите на этот код
**Inside FutureTask$Sync**
void innerRun() {
if (!compareAndSetState(READY, RUNNING))
return;
runner = Thread.currentThread();
if (getState() == RUNNING) { // recheck after setting thread
V result;
try {
result = callable.call();
} catch (Throwable ex) {
setException(ex);
return;
}
set(result);
} else {
releaseShared(0); // cancel
}
}
protected void setException(Throwable t) {
sync.innerSetException(t);
}
Посмотрите на этот пост SE и этот вопрос SE:
Выберите между отправкой ExecutorService и выполнением ExecutorService
Попробуйте поставить sysout после submit(...) и посмотрите, будет ли это напечатано. Это означает, что родительский / основной поток не заблокирован в методе call() и возвращен сразу после отправки задачи.
Вы можете захватить Future, возвращенный методом submit, и добавить следующий код после вызова метода submit:
try {
future.get();
}catch(ExecutionException ee){
System.out.println("exception >>" + ee.getMessage());
}
service.shutdown();
Поскольку future.get является блокирующим вызовом, поток, отправляющий задачу, будет ожидать завершения асинхронной операции. Вы также узнаете, есть ли какие-то исключения.
FutureTask хранит исключение в переменной, которая затем будет заключена в ExecutionException и выброшена при вызове метода get. Таким образом, мы можем получить основное исключение, даже когда мы вызываем метод get() для FutureTask