ejemplos - java futuretask
¿Cuál es la diferencia entre Future y FutureTask en Java? (5)
Dado que el uso de ExecutorService
puede submit
una tarea Callable
y devolver un Future
, ¿por qué necesitamos usar FutureTask
para envolver la tarea Callable
y usar el método execute
? Siento que ambos hacen lo mismo.
Como Mark, y otros, respondieron correctamente que Future
es la interfaz para FutureTask
y Executor
efectivamente su fábrica; lo que significa que el código de la aplicación raramente FutureTask
instancia de FutureTask
directamente. Para complementar la discusión, proporciono un ejemplo que muestra una situación en la que FutureTask
se construye y utiliza directamente, fuera de cualquier Executor
:
FutureTask<Integer> task = new FutureTask<Integer>(()-> {
System.out.println("Pretend that something complicated is computed");
Thread.sleep(1000);
return 42;
});
Thread t1 = new Thread(()->{
try {
int r = task.get();
System.out.println("Result is " + r);
} catch (InterruptedException | ExecutionException e) {}
});
Thread t2 = new Thread(()->{
try {
int r = task.get();
System.out.println("Result is " + r);
} catch (InterruptedException | ExecutionException e) {}
});
Thread t3 = new Thread(()->{
try {
int r = task.get();
System.out.println("Result is " + r);
} catch (InterruptedException | ExecutionException e) {}
});
System.out.println("Several threads are going to wait until computations is ready");
t1.start();
t2.start();
t3.start();
task.run(); // let the main thread to compute the value
Aquí, FutureTask
se usa como una herramienta de sincronización, como CountdownLatch
o una barrera similar. Se podría haber vuelto a implementar utilizando CountdownLatch
o bloqueos y condiciones; FutureTask
simplemente lo hace muy bien encapsulado, se explica por sí mismo, es elegante y con menos código.
También tenga en cuenta que el método FutureTask # run () debe llamarse explícitamente, en cualquiera de los subprocesos; No hay Ejecutor alrededor para hacerlo por ti. En mi código, finalmente lo ejecuta el subproceso principal, pero se puede modificar el método get()
para llamar a run()
en el primer subproceso que llama a get()
, por lo tanto, el primer subproceso que llega a get()
, y puede ser cualquiera de T1, T2 o T3, harían el cálculo para todos los hilos restantes.
En esta idea, el primer hilo que solicita el resultado haría el cálculo para otros, mientras que los intentos concurrentes se bloquearían, se basa en Memoizer, vea el ejemplo de Memoizer Cache de la página 108 en "Java Concurrency in Practice".
De hecho tienes razón. Los dos enfoques son idénticos. Por lo general, no necesitas envolverlos tú mismo. Si es así, es probable que esté duplicando el código en AbstractExecutorService:
/**
* Returns a <tt>RunnableFuture</tt> for the given callable task.
*
* @param callable the callable task being wrapped
* @return a <tt>RunnableFuture</tt> which when run will call the
* underlying callable and which, as a <tt>Future</tt>, will yield
* the callable''s result as its result and provide for
* cancellation of the underlying task.
* @since 1.6
*/
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
La única diferencia entre Future y RunnableFuture es el método run ():
/**
* A {@link Future} that is {@link Runnable}. Successful execution of
* the <tt>run</tt> method causes completion of the <tt>Future</tt>
* and allows access to its results.
* @see FutureTask
* @see Executor
* @since 1.6
* @author Doug Lea
* @param <V> The result type returned by this Future''s <tt>get</tt> method
*/
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
Una buena razón para dejar que el Ejecutor construya la Tarea del Futuro por usted es asegurarse de que no haya ninguna posibilidad de que exista más de una referencia a la instancia de la Tarea del Futuro. Es decir, el Ejecutor posee esta instancia.
Solo necesitaría usar FutureTask si desea cambiar su comportamiento o acceder a su Callable más adelante. Para el 99% de los usos, solo usa Callable y Future.
FutureTask Esta clase proporciona una base implementation of Future
, con métodos para iniciar y cancelar un cálculo.
Future es la interfaz.
Future
es solo la interfaz. Detrás del escenario, la implementación es FutureTask
.
Absolutamente puede usar FutureTask
manualmente pero perderá las ventajas de usar Executor
(agrupación de hilos, límite de hilos, etc.). Usar FutureTask
es bastante similar a usar el Thread
antiguo y usar el método de ejecución .