La interfaz invocable es similar a Runnable, ya que ambas están diseñadas para clases cuyas instancias son potencialmente ejecutadas por otro subproceso. Un Runnable, sin embargo, no devuelve un resultado y no puede lanzar una excepción marcada.
¿Cuál es la necesidad de tener ambos si Callablepuede hacer todo lo que Runnablehace?
¡Porque la Runnableinterfaz no puede hacer todo lo que Callablehace!
Runnableha existido desde Java 1.0, pero Callablesolo se introdujo en Java 1.5 ... para manejar casos de uso que Runnableno son compatibles. En teoría, el equipo de Java podría haber cambiado la firma del Runnable.run()método, pero esto habría roto la compatibilidad binaria con el código anterior a 1.5, lo que requeriría la codificación al migrar el código de Java antiguo a las JVM más nuevas. Eso es un GRAN NO-NO. Java se esfuerza por ser compatible con versiones anteriores ... y ese ha sido uno de los mayores puntos de venta de Java para la informática empresarial.
Y, obviamente, hay casos de uso donde una tarea no necesita devolver un resultado o lanzar una excepción marcada. Para esos casos de uso, usar Runnablees más conciso que usar Callable<Void>y devolver un nullvalor ficticio ( ) del call()método.
Me pregunto de dónde sacaste esta historia. Esto es muy útil
Spiderman
44
@prash: los datos básicos se encuentran en los libros de texto antiguos. Como la primera edición de Java in a Nutshell.
Stephen C
44
(@prash - También ... al comenzar a usar Java en la era Java 1.1.)
Stephen C
1
@StephenC Si leí tu respuesta correctamente, estás sugiriendo que Runnableexiste (en gran parte) por razones de compatibilidad con versiones anteriores. Pero, ¿no hay situaciones en las que sea innecesario o demasiado costoso implementar (o requerir) la Callableinterfaz (por ejemplo, en ScheduledFuture<?> ScheduledExecutorService.schedule(Runnable command, long delay, TimeUnit unit))? Entonces, ¿no hay un beneficio en mantener ambas interfaces en el idioma, incluso si la historia no forzó el resultado actual?
max
1
@max - Bueno, dije eso, y todavía estoy de acuerdo con eso. Sin embargo, esa es una razón secundaria. Pero aun así, sospecho que Runnablese habría modificado si no hubiera habido un imperativo para mantener la compatibilidad. El "repetitivo" de return null;es un argumento débil. (Al menos, esa habría sido mi decisión ... en el contexto hipotético en el que podría ignorar la compatibilidad con versiones anteriores.)
Stephen C
82
A Callablenecesita implementar el call()método mientras que Runnablenecesita implementar el run()método.
A Callablepuede devolver un valor pero a Runnableno puede.
A Callablepuede lanzar una excepción marcada pero Runnableno puede.
A Callablese puede usar con ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)métodos pero a Runnableno se puede.
publicinterfaceRunnable{void run();}publicinterfaceCallable<V>{
V call()throwsException;}
ExecutorService.submit (tarea ejecutable) también existe y es muy útil
Yair Kukielka
Runnable también se puede usar con ExecutorService de la siguiente manera: 1) ExecutorService.execute (Runnable) 2) ExecutorService.submit (Runnable)
Azam Khan
2
También hay Executor.submit (tarea invocable <T>) pero no puede invocar All o invokeAny con la colección de tareas ejecutables Collection <? extiende las tareas <T>>
invocables
36
Encontré esto en otro blog que puede explicar un poco más estas diferencias :
Aunque ambas interfaces son implementadas por las clases que desean ejecutar en un hilo de ejecución diferente, pero hay algunas diferencias entre las dos interfaces que son:
Una Callable<V>instancia devuelve un resultado de tipo V, mientras que una Runnableinstancia no.
Una Callable<V>instancia puede arrojar excepciones marcadas, mientras que una Runnableinstancia no puede
Los diseñadores de Java sintieron la necesidad de ampliar las capacidades de la Runnableinterfaz, pero no querían afectar los usos de la Runnableinterfaz y probablemente esa fue la razón por la que optaron por tener una interfaz separada nombrada Callableen Java 1.5 en lugar de cambiar existente Runnable.
Runnable y Callable se ejecutan en un subproceso diferente que el subproceso de llamada. Pero Callable puede devolver un valor y Runnable no. Entonces, ¿dónde se aplica esto realmente?
Runnable : si tiene un incendio y olvida la tarea, use Runnable. Coloque su código dentro de un Runnable y cuando se llame al método run (), puede realizar su tarea. El hilo de llamada realmente no le importa cuando realiza su tarea.
Invocable : si está intentando recuperar un valor de una tarea, use Invocable. Ahora invocable por sí solo no hará el trabajo. Necesitará un futuro que envuelva su invocable y obtenga sus valores en future.get (). Aquí el hilo de llamada se bloqueará hasta que el futuro regrese con resultados que a su vez están esperando que se ejecute el método call () de Callable.
Así que piense en una interfaz para una clase de destino donde tenga definidos los métodos ajustables Runnable y Callable. La clase que realiza la llamada llamará aleatoriamente a sus métodos de interfaz sin saber cuál es Runnable y cuál es invocable. Los métodos Runnable se ejecutarán de forma asíncrona, hasta que se llame a un método invocable. Aquí el hilo de la clase que llama se bloqueará ya que está recuperando valores de su clase objetivo.
NOTA: Dentro de su clase de destino, puede realizar llamadas a Callable y Runnable en un único ejecutor de subprocesos, lo que hace que este mecanismo sea similar a una cola de despacho en serie. Por lo tanto, mientras la persona que llama llame a sus métodos envueltos Runnable, el hilo de llamada se ejecutará realmente rápido sin bloqueo. Tan pronto como llame a un método invocable envuelto en el futuro, tendrá que bloquear hasta que se ejecuten todos los demás elementos en cola. Solo entonces el método volverá con valores. Este es un mecanismo de sincronización.
CallableLa interfaz declara el call()método y debe proporcionar los genéricos, ya que el tipo de Object call () debería devolver:
publicinterfaceCallable<V>{/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call()throwsException;}
RunnablePor otro lado, hay una interfaz que declara el run()método al que se llama cuando se crea un subproceso con el ejecutable y se llama a start (). También puede llamar directamente a run () pero eso solo ejecuta el método run () es el mismo hilo.
publicinterfaceRunnable{/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/publicabstractvoid run();}
Para resumir algunas diferencias notables son
Un Runnableobjeto no devuelve un resultado, mientras que un Callableobjeto devuelve un resultado.
Un Runnableobjeto no puede lanzar una excepción marcada cuando un Callableobjeto puede lanzar una excepción.
La Runnableinterfaz ha existido desde Java 1.0, mientras que Callablesolo se introdujo en Java 1.5.
Pocas similitudes incluyen
Las instancias de las clases que implementan interfaces ejecutables o invocables son ejecutadas potencialmente por otro subproceso.
ExecutorService puede ejecutar la instancia de las interfaces ejecutables y ejecutables mediante el método submit ().
Ambas son interfaces funcionales y se pueden usar en expresiones Lambda desde Java8.
Los métodos en la interfaz ExecutorService son
<T>Future<T> submit(Callable<T> task);Future<?> submit(Runnable task);<T>Future<T> submit(Runnable task, T result);
Propósito de estas interfaces de la documentación de Oracle:
La interfaz ejecutable debe ser implementada por cualquier clase cuyas instancias estén destinadas a ser ejecutadas por a Thread. La clase debe definir un método sin argumentos invocados run.
Llamable : una tarea que devuelve un resultado y puede arrojar una excepción. Los implementadores definen un método único sin argumentos llamado llamada. La Callableinterfaz es similar Runnable, ya que ambas están diseñadas para clases cuyas instancias son potencialmente ejecutadas por otro hilo. A Runnable, sin embargo, no devuelve un resultado y no puede lanzar una excepción marcada.
Otras diferencias
Puede pasar Runnablepara crear un hilo . Pero no puede crear un nuevo hilo pasando Callablecomo parámetro. Puede pasar invocable solo a ExecutorServiceinstancias.
publicclassHelloRunnableimplementsRunnable{publicvoid run(){System.out.println("Hello from a thread!");}publicstaticvoid main(String args[]){(newThread(newHelloRunnable())).start();}}
Úselo Runnablepara disparar y olvidar llamadas. Use Callablepara verificar el resultado.
Callablese puede pasar al método invokeAll a diferencia de Runnable. Métodos invokeAnyy invokeAllrealizar las formas más comunes de ejecución masiva, ejecutar una colección de tareas y luego esperar al menos una, o todas, para completar
Diferencia trivial: nombre del método a implementar => run()para Runnabley call()para Callable.
Como ya se mencionó aquí, Callable es una interfaz relativamente nueva y se introdujo como parte del paquete de concurrencia. Tanto Callable como Runnable se pueden usar con ejecutores. Class Thread (que implementa Runnable) solo admite Runnable.
Todavía puede usar Runnable con ejecutores. La ventaja de Callable es que puede enviarlo al ejecutor e inmediatamente recuperar el resultado futuro que se actualizará cuando finalice la ejecución. Lo mismo puede implementarse con Runnable, pero en este caso debe administrar los resultados usted mismo. Por ejemplo, puede crear una cola de resultados que contendrá todos los resultados. Otro hilo puede esperar en esta cola y lidiar con los resultados que llegan.
Me pregunto cuál es el ejemplo en un hilo lanzando una excepción en Java. ¿podrá el hilo principal captar esa excepción? Si no, no usaría Callable. Alex, ¿tienes alguna idea sobre esto? ¡Gracias!
trillones
1
El código que se ejecuta en un subproceso personalizado como cualquier otro código puede generar una excepción. Para atraparlo en otro hilo, debe realizar algunos esfuerzos, ya sea mediante el uso de un mecanismo de notificación personalizado (por ejemplo, basado en oyentes) o mediante el uso Futureo agregando gancho que capture todas las excepciones no adquiridas
AlexR
Gran información! Gracias Alex! :)
billones
1
Voté esta respuesta porque afirma (correctamente si se toma al pie de la letra) uno debe usar el modelo de grupo de subprocesos con objetos invocables. Lo aparentemente desafortunado de esto es que no se puede extender Threadpara hacer un uso significativo de la Callableinterfaz para que un solo hilo se pueda personalizar para hacer cosas invocables y otras cosas que el desarrollador pueda desear. Si alguien que lee este comentario piensa que estoy equivocado, me gustaría saberlo mejor ...
8
+-------------------------------------+--------------------------------------------------------------------------------------------------+|Runnable|Callable<T>|+-------------------------------------+--------------------------------------------------------------------------------------------------+|Introduced in Java1.0 of java.lang |Introduced in Java1.5 of java.util.concurrent library ||Runnable cannot be parametrized |Callable is a parametrized type whose type parameter indicates the return type of its run method ||Runnable has run() method |Callable has call() method ||Runnable.run() returns void|Callable.call() returns a value of Type T ||Can not throwCheckedExceptions|CanthrowCheckedExceptions|+-------------------------------------+--------------------------------------------------------------------------------------------------+
Los diseñadores de Java sintieron la necesidad de ampliar las capacidades de la Runnableinterfaz, pero no querían afectar los usos de la Runnableinterfaz y probablemente esa fue la razón por la que optaron por tener una interfaz separada nombrada Callableen Java 1.5 en lugar de cambiar Runnableinterfaz existente que ha sido parte de Java desde Java 1.0. fuente
Es importante enfatizar que la Excepción marcada , no la RuntimeException
BertKing
5
Callable y Runnable, ambos son similares entre sí y pueden usarse para implementar hilos. En el caso de implementar Runnable , debe implementar el método run () , pero en el caso de invocables, debe implementar el método call () , ambos métodos funcionan de manera similar, pero el método invocable call () tiene más flexibilidad. Hay algunas diferencias entre ellos.
Diferencia entre Runnable y invocable como a continuación:
1) El método run () de runnable devuelve void , significa que si desea que su hilo devuelva algo que pueda usar aún más, entonces no tiene otra opción con el método Runnable run () . Hay una solución 'Callable' . Si desea devolver algo en forma de objeto , debe usar Callable en lugar de Runnable . La interfaz invocable tiene el método 'call ()' que devuelve Object .
Firma del método - Ejecutable->
publicvoid run(){}
Llamable->
publicObject call(){}
2) En caso de ejecución Ejecutable () método si ninguna excepción comprobada surge entonces debe ser pasadas de bloque con intento de captura , pero en caso de llamada rescatable () método que puede lanzar excepción comprobada la siguiente
publicObject call()throwsException{}
3) Runnable proviene de la versión legacy java 1.0 , pero invocable vino en la versión Java 1.5 con el marco Executer .
Si está familiarizado con Executers, entonces debe usar Callable en lugar de Runnable .
Runnable (vs) Callable entra en juego cuando usamos el framework Executer.
ExecutorService es una subinterfaz de Executor, que acepta tareas ejecutables y ejecutables.
Se puede lograr un subproceso múltiple anterior utilizando la interfaz desde 1.0 , pero aquí el problema es después de completar la tarea de subproceso, no podemos recopilar la información de subprocesos. Para recopilar los datos, podemos usar campos estáticos.Runnable
Ejemplo Hilos separados para recopilar datos de cada alumno.
staticHashMap<String,List> multiTasksData =newHashMap();publicstaticvoid main(String[] args){Thread t1 =newThread(newRunnableImpl(1),"T1");Thread t2 =newThread(newRunnableImpl(2),"T2");Thread t3 =newThread(newRunnableImpl(3),"T3");
multiTasksData.put("T1",newArrayList());// later get the value and update it.
multiTasksData.put("T2",newArrayList());
multiTasksData.put("T3",newArrayList());}
Para resolver este problema, han introducido Since 1.5 que devuelve un resultado y puede arrojar una excepción.Callable<V>
Método abstracto único : tanto la interfaz invocable como la ejecutable tienen un único método abstracto, lo que significa que pueden usarse en expresiones lambda en java 8.
Respuestas:
Ver explicación aquí .
fuente
Básicamente sí. Ver las respuestas a esta pregunta . Y el javadoc para
Callable
.¡Porque la
Runnable
interfaz no puede hacer todo lo queCallable
hace!Runnable
ha existido desde Java 1.0, peroCallable
solo se introdujo en Java 1.5 ... para manejar casos de uso queRunnable
no son compatibles. En teoría, el equipo de Java podría haber cambiado la firma delRunnable.run()
método, pero esto habría roto la compatibilidad binaria con el código anterior a 1.5, lo que requeriría la codificación al migrar el código de Java antiguo a las JVM más nuevas. Eso es un GRAN NO-NO. Java se esfuerza por ser compatible con versiones anteriores ... y ese ha sido uno de los mayores puntos de venta de Java para la informática empresarial.Y, obviamente, hay casos de uso donde una tarea no necesita devolver un resultado o lanzar una excepción marcada. Para esos casos de uso, usar
Runnable
es más conciso que usarCallable<Void>
y devolver unnull
valor ficticio ( ) delcall()
método.fuente
Runnable
existe (en gran parte) por razones de compatibilidad con versiones anteriores. Pero, ¿no hay situaciones en las que sea innecesario o demasiado costoso implementar (o requerir) laCallable
interfaz (por ejemplo, enScheduledFuture<?> ScheduledExecutorService.schedule(Runnable command, long delay, TimeUnit unit)
)? Entonces, ¿no hay un beneficio en mantener ambas interfaces en el idioma, incluso si la historia no forzó el resultado actual?Runnable
se habría modificado si no hubiera habido un imperativo para mantener la compatibilidad. El "repetitivo" dereturn null;
es un argumento débil. (Al menos, esa habría sido mi decisión ... en el contexto hipotético en el que podría ignorar la compatibilidad con versiones anteriores.)Callable
necesita implementar elcall()
método mientras queRunnable
necesita implementar elrun()
método.Callable
puede devolver un valor pero aRunnable
no puede.Callable
puede lanzar una excepción marcada peroRunnable
no puede.A
Callable
se puede usar conExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)
métodos pero aRunnable
no se puede.fuente
Encontré esto en otro blog que puede explicar un poco más estas diferencias :
Aunque ambas interfaces son implementadas por las clases que desean ejecutar en un hilo de ejecución diferente, pero hay algunas diferencias entre las dos interfaces que son:
Callable<V>
instancia devuelve un resultado de tipoV
, mientras que unaRunnable
instancia no.Callable<V>
instancia puede arrojar excepciones marcadas, mientras que unaRunnable
instancia no puedeLos diseñadores de Java sintieron la necesidad de ampliar las capacidades de la
Runnable
interfaz, pero no querían afectar los usos de laRunnable
interfaz y probablemente esa fue la razón por la que optaron por tener una interfaz separada nombradaCallable
en Java 1.5 en lugar de cambiar existenteRunnable
.fuente
Veamos dónde se usarían Runnable y Callable.
Runnable y Callable se ejecutan en un subproceso diferente que el subproceso de llamada. Pero Callable puede devolver un valor y Runnable no. Entonces, ¿dónde se aplica esto realmente?
Runnable : si tiene un incendio y olvida la tarea, use Runnable. Coloque su código dentro de un Runnable y cuando se llame al método run (), puede realizar su tarea. El hilo de llamada realmente no le importa cuando realiza su tarea.
Invocable : si está intentando recuperar un valor de una tarea, use Invocable. Ahora invocable por sí solo no hará el trabajo. Necesitará un futuro que envuelva su invocable y obtenga sus valores en future.get (). Aquí el hilo de llamada se bloqueará hasta que el futuro regrese con resultados que a su vez están esperando que se ejecute el método call () de Callable.
Así que piense en una interfaz para una clase de destino donde tenga definidos los métodos ajustables Runnable y Callable. La clase que realiza la llamada llamará aleatoriamente a sus métodos de interfaz sin saber cuál es Runnable y cuál es invocable. Los métodos Runnable se ejecutarán de forma asíncrona, hasta que se llame a un método invocable. Aquí el hilo de la clase que llama se bloqueará ya que está recuperando valores de su clase objetivo.
NOTA: Dentro de su clase de destino, puede realizar llamadas a Callable y Runnable en un único ejecutor de subprocesos, lo que hace que este mecanismo sea similar a una cola de despacho en serie. Por lo tanto, mientras la persona que llama llame a sus métodos envueltos Runnable, el hilo de llamada se ejecutará realmente rápido sin bloqueo. Tan pronto como llame a un método invocable envuelto en el futuro, tendrá que bloquear hasta que se ejecuten todos los demás elementos en cola. Solo entonces el método volverá con valores. Este es un mecanismo de sincronización.
fuente
Callable
La interfaz declara elcall()
método y debe proporcionar los genéricos, ya que el tipo de Object call () debería devolver:Runnable
Por otro lado, hay una interfaz que declara elrun()
método al que se llama cuando se crea un subproceso con el ejecutable y se llama a start (). También puede llamar directamente a run () pero eso solo ejecuta el método run () es el mismo hilo.Para resumir algunas diferencias notables son
Runnable
objeto no devuelve un resultado, mientras que unCallable
objeto devuelve un resultado.Runnable
objeto no puede lanzar una excepción marcada cuando unCallable
objeto puede lanzar una excepción.Runnable
interfaz ha existido desde Java 1.0, mientras queCallable
solo se introdujo en Java 1.5.Pocas similitudes incluyen
Los métodos en la interfaz ExecutorService son
fuente
Propósito de estas interfaces de la documentación de Oracle:
La interfaz ejecutable debe ser implementada por cualquier clase cuyas instancias estén destinadas a ser ejecutadas por a
Thread
. La clase debe definir un método sin argumentos invocadosrun
.Llamable : una tarea que devuelve un resultado y puede arrojar una excepción. Los implementadores definen un método único sin argumentos llamado llamada. La
Callable
interfaz es similarRunnable
, ya que ambas están diseñadas para clases cuyas instancias son potencialmente ejecutadas por otro hilo. ARunnable
, sin embargo, no devuelve un resultado y no puede lanzar una excepción marcada.Otras diferencias
Puede pasar
Runnable
para crear un hilo . Pero no puede crear un nuevo hilo pasandoCallable
como parámetro. Puede pasar invocable solo aExecutorService
instancias.Ejemplo:
Úselo
Runnable
para disparar y olvidar llamadas. UseCallable
para verificar el resultado.Callable
se puede pasar al método invokeAll a diferencia deRunnable
. MétodosinvokeAny
yinvokeAll
realizar las formas más comunes de ejecución masiva, ejecutar una colección de tareas y luego esperar al menos una, o todas, para completarDiferencia trivial: nombre del método a implementar =>
run()
paraRunnable
ycall()
paraCallable
.fuente
Como ya se mencionó aquí, Callable es una interfaz relativamente nueva y se introdujo como parte del paquete de concurrencia. Tanto Callable como Runnable se pueden usar con ejecutores. Class Thread (que implementa Runnable) solo admite Runnable.
Todavía puede usar Runnable con ejecutores. La ventaja de Callable es que puede enviarlo al ejecutor e inmediatamente recuperar el resultado futuro que se actualizará cuando finalice la ejecución. Lo mismo puede implementarse con Runnable, pero en este caso debe administrar los resultados usted mismo. Por ejemplo, puede crear una cola de resultados que contendrá todos los resultados. Otro hilo puede esperar en esta cola y lidiar con los resultados que llegan.
fuente
Future
o agregando gancho que capture todas las excepciones no adquiridasThread
para hacer un uso significativo de laCallable
interfaz para que un solo hilo se pueda personalizar para hacer cosas invocables y otras cosas que el desarrollador pueda desear. Si alguien que lee este comentario piensa que estoy equivocado, me gustaría saberlo mejor ...Los diseñadores de Java sintieron la necesidad de ampliar las capacidades de la
Runnable
interfaz, pero no querían afectar los usos de laRunnable
interfaz y probablemente esa fue la razón por la que optaron por tener una interfaz separada nombradaCallable
en Java 1.5 en lugar de cambiarRunnable
interfaz existente que ha sido parte de Java desde Java 1.0. fuentefuente
Las diferencias entre Callable y Runnable son las siguientes:
fuente
Callable y Runnable, ambos son similares entre sí y pueden usarse para implementar hilos. En el caso de implementar Runnable , debe implementar el método run () , pero en el caso de invocables, debe implementar el método call () , ambos métodos funcionan de manera similar, pero el método invocable call () tiene más flexibilidad. Hay algunas diferencias entre ellos.
Diferencia entre Runnable y invocable como a continuación:
1) El método run () de runnable devuelve void , significa que si desea que su hilo devuelva algo que pueda usar aún más, entonces no tiene otra opción con el método Runnable run () . Hay una solución 'Callable' . Si desea devolver algo en forma de objeto , debe usar Callable en lugar de Runnable . La interfaz invocable tiene el método 'call ()' que devuelve Object .
Firma del método - Ejecutable->
Llamable->
2) En caso de ejecución Ejecutable () método si ninguna excepción comprobada surge entonces debe ser pasadas de bloque con intento de captura , pero en caso de llamada rescatable () método que puede lanzar excepción comprobada la siguiente
3) Runnable proviene de la versión legacy java 1.0 , pero invocable vino en la versión Java 1.5 con el marco Executer .
Si está familiarizado con Executers, entonces debe usar Callable en lugar de Runnable .
Espero que entiendas.
fuente
Runnable (vs) Callable entra en juego cuando usamos el framework Executer.
ExecutorService es una subinterfaz de
Executor
, que acepta tareas ejecutables y ejecutables.Se puede lograr un subproceso múltiple anterior utilizando la interfaz desde 1.0 , pero aquí el problema es después de completar la tarea de subproceso, no podemos recopilar la información de subprocesos. Para recopilar los datos, podemos usar campos estáticos.
Runnable
Ejemplo Hilos separados para recopilar datos de cada alumno.
Para resolver este problema, han introducido Since 1.5 que devuelve un resultado y puede arrojar una excepción.
Callable<V>
Método abstracto único : tanto la interfaz invocable como la ejecutable tienen un único método abstracto, lo que significa que pueden usarse en expresiones lambda en java 8.
Hay algunas formas diferentes de delegar tareas para su ejecución a un ExecutorService .
execute(Runnable task):void
crea un nuevo hilo pero no bloquea el hilo principal o el hilo de la persona que llama, ya que este método devuelve nulo.submit(Callable<?>):Future<?>
,submit(Runnable):Future<?>
crea un nuevo hilo y bloquea el hilo principal cuando está utilizando future.get () .Ejemplo de uso de interfaces ejecutables, invocables con el marco de ejecución.
fuente
Es una especie de convención de nomenclatura de interfaz que coincide con la programación funcional.
fuente