java.util.concurrent.future.get () non ritorna
-
24-09-2019 - |
Domanda
Ho il seguente codice Java:
final Future future = exeService.submit(
new Runnable() {
public void run() {
myObject.doSomething();
}
}
);
future.get();
dove exeService
è un'istanza di
java.util.concurrent.ExecutorService
Il problema è che myObject.doSomething()
non ritorna mai e, quindi, future.get()
Non ritorna mai.
Tuttavia, se sostituisco la chiamata a submit
con una chiamata a execute
come questo:
exeService.execute(
new Runnable() {
public void run() {
myObject.doSomething();
}
}
);
la chiamata a myObject.doSomething()
torna. Non so se è importante, ma doSomething()
è un void
metodo.
Perché è doSomething()
finire quando si usa execute
ma non quando si usa submit
?
Inoltre, non ho bisogno di usare Future.get()
; Sembrava essere il modo più naturale per farlo. (Mi imbatto anche nello stesso problema con CountdownLatch
.) Il punto è che devo aspettare doSomething()
Per finire prima di procedere e, per motivi complicati non andrò qui, devo lanciarlo su un thread separato. Se c'è un altro modo di farlo che funzioni, andrebbe bene.
Soluzione
Come in Executor.execute () Javadoc:
Esegue il comando indicato in qualche momento in futuro. Il comando può eseguire in un nuovo thread, in un thread pool o nel thread chiamante, a discrezione dell'implementazione dell'esecutore.
Quindi, il metodo execute()
Restituisce immediatamente lasciandoti senza opzione per interrogare lo stato dell'attività inviata.
D'altro canto ExecutoService.submit ():
Invia un'attività eseguibile per l'esecuzione e restituisce un futuro che rappresenta tale attività. Il metodo Get del futuro restituirà null al completamento con successo.
Il Future.get () tornerà solo Dopo una competizione di successo, così mai nel tuo caso.
Questo è ulteriormente notato in Future.get () documentazione:
Attende se necessario per il completamento del calcolo, quindi recupera il suo risultato.
Altri suggerimenti
Ho creato un SSCCE:
package com.stackoverflow.q2585971;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Test {
public static void main(String args[]) throws Exception {
ExecutorService executor = Executors.newCachedThreadPool();
Future<?> future = executor.submit(
new Runnable() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Epic fail.");
}
}
}
);
System.out.println("Waiting for task to finish..");
future.get();
System.out.println("Task finished!");
executor.shutdown();
}
}
Funziona perfettamente bene. Prima stampe
Waiting for task to finish..
poi dopo un secondo vedi
Task finished!
Quindi, il tuo problema sta altrove. Duplicherò il mio commento sulla tua domanda qui:
La tua domanda è piuttosto confusa. Il primo costrutto dovrebbe funzionare. La confusione è in "ritorno". Non intendi solo "finire" o "eseguire"? La tua confusione sembra basarsi sul fatto che
future.get()
In realtà attende che il runnable sia finito e quindi bloccherà il thread e impedirà che esegui il residuo del codice dopo ilfuture.get()
linea.
I futures Java stanno bloccando! get(). This method blocks the current thread until a future instance completes its work, thus requiring the use of one thread more than the work that must be performed just to manage what happens when it is done