Cuando llamamos a una función, si la ejecución de esta función lleva mucho tiempo, tenemos que esperar, pero a veces no tenemos prisa por obtener el resultado devuelto por esta función. Por lo tanto, podemos dejar que la persona que llama regrese inmediatamente y procesar lentamente la solicitud en segundo plano. Para la persona que llama, puede ocuparse de algunas otras cosas primero y luego intentar obtener los datos requeridos cuando los datos realmente sean necesarios (la ubicación donde realmente se necesitan los datos es el punto de bloqueo mencionado anteriormente). Esta es también la idea central del patrón Future: llamadas asincrónicas.
En este punto, ¿puedes estar pensando que CountDownLatch también puede implementar funciones similares? También puede dejar que las tareas que requieren mucho tiempo se ejecuten a través de subprocesos y luego establecer un punto de bloqueo para esperar los resultados. ¡La situación parece ser así! Pero a veces se descubre que no es suficiente que CountDownLatch solo conozca el estado de finalización del subproceso. Si los resultados del cálculo del subproceso se obtienen después de completar el subproceso, entonces CountDownLatch está algo estirado. Por lo tanto, la clase Future proporcionada por JDK no solo se puede completar en el subproceso después de recopilar los resultados, sino que también puede establecer el tiempo de espera del subproceso para evitar que la tarea principal espere todo el tiempo.
¡Al ver esto, parece que de repente me di cuenta! CountDownLatch no puede tener una buena idea de los resultados de la ejecución del subproceso. Esta operación se puede completar usando Future, entonces, ¿dónde está Future? Hablemos de ello en detalle a continuación.
Aunque el modo Futuro no devolverá inmediatamente los datos que necesita, le devolverá un contrato a través del cual podrá obtener los datos requeridos cuando los datos se utilicen en el futuro.
La figura anterior muestra el proceso de una llamada a un programa en serie. Se puede ver que cuando la ejecución de un programa requiere mucho tiempo, otros programas deben esperar hasta que finalice la operación que requiere mucho tiempo. En este caso, el cliente debe esperar hasta que se devuelvan los datos antes de realizar otras tareas.
La imagen de arriba muestra el diagrama de flujo del modo Futuro. En el modo Futuro amplio, aunque la obtención de datos es una operación que requiere mucho tiempo, el programa de servicio devuelve inmediatamente datos falsificados al cliente sin esperar a que lleguen los datos. (Este es el "contrato" mencionado anteriormente). El cliente que implementa el modo Futuro no tiene prisa por procesarlo, sino que maneja otros negocios primero, aprovechando al máximo el tiempo de espera. núcleo del modo Futuro Después de completar Después de completar otras tareas independientes de los datos, finalmente use los datos futuros más lentos para devolver. De esta forma, no habrá largas esperas durante todo el proceso de llamada, aprovechando al máximo el tiempo, mejorando así la eficiencia del sistema.
1. El papel principal de Future
2. El diagrama de estructura central de Future es el siguiente:
El proceso anterior significa: Los datos son la interfaz principal , que es el cliente Los datos que espera obtener, en el modo Futuro, esta interfaz de Datos tiene dos implementaciones importantes, a saber: RealData y FutureData. RealData son datos reales. FutureData es una implementación de interfaz que se utiliza para extraer datos reales de RealData y los devuelve inmediatamente. En realidad, es un proxy para RealData de datos reales, que encapsula el proceso de espera para obtener RealData.
Habiendo dicho estas cosas teóricas, sería más sencillo mirar el código directamente. ¡Mire el código!
Incluye principalmente las siguientes 5 clases, correspondientes a las funciones principales del modo Futuro:
1. Interfaz de datos
2. Código FutureData
3. Código RealData
4. Código de cliente
5. Principal
6. Resultado de la ejecución:
Lo anterior implementa un simple La implementación del modo Futuro, debido a que este es un modo muy utilizado, el JDK también nos proporciona los métodos e interfaces correspondientes. Primero echemos un vistazo a los ejemplos:
Aquí se implementa RealData. la interfaz invocable. Repetir Se escribe el método de llamada y la operación que requiere mucho tiempo para construir datos reales se implementa en el método de llamada.
Resultado de la ejecución:
El código anterior pasa: FutureTasklt; Stringgt; FutureTask = new FutureTasklt; lo que indica que esta tarea tiene un valor de retorno y el tipo de retorno es String. Echemos un vistazo a la relación del diagrama de clases de FutureTask:
FutureTask implementa la interfaz RunnableFuture, y la interfaz RunnableFuture hereda Future y Runnable. interfaces. Debido a que RunnableFuture implementa la interfaz Runnable, FutureTask se puede enviar a Executor para su ejecución. FutureTask tiene dos métodos de construcción, de la siguiente manera:
Método de construcción 1, el parámetro es invocable:
Método de construcción. 2, el parámetro es Runnable:
En el segundo método de construcción anterior, si se pasa la interfaz Runnable, se convertirá en Callable a través del método Executors.callable(). El proceso de adaptación es el siguiente. :
¿Por qué necesitamos convertir Runnable en Callable aquí? Primero, echemos un vistazo a la diferencia entre los dos:
El punto más importante es el segundo punto, que es que Callable tiene un valor de retorno, mientras que Runnable no tiene valor de retorno. Callable proporciona métodos para verificar si el cálculo se completa, esperar a que se complete y obtener el resultado del cálculo.
Una vez completado el cálculo, solo puede utilizar el método get para obtener el resultado. Si el hilo no ha terminado de ejecutarse, el método Future.get() puede bloquear la ejecución del hilo actual; se produce una excepción en el hilo, Future.get() arrojará InterruptedException o ExecutionException si el hilo ha sido cancelado, se lanzará CancellationException; La cancelación se realiza mediante el método de cancelación. isDone determina si la tarea se completó normalmente o se canceló.