java8 futures java concurrency future

java8 - futures in java



Caso de uso para Future.cancel(falso)? (3)

¿En qué situación se quiere pasar false para el parámetro Future.cancel() a Future.cancel() ?

Si entiendo correctamente, si pasa false y la tarea se cancela pero el hilo no se interrumpe, el resultado (o ExecutionException ) nunca será accesible porque la tarea todavía se marca como cancelada (es decir, isCancelled() devuelve true y get() lanza CancellationException )

Otras posibles situaciones son:

  • La implementación Runnable o Callable no verifica las interrupciones y se ejecutará hasta su finalización incluso si la interrumpe (aquí la interrupción no hace diferencia)
  • La tarea ya se completó antes de llamar a cancel() (de nuevo la interrupción no hace diferencia)
  • La tarea necesita realizar alguna limpieza antes de que se cierre (una implementación bien escrita usará try ... finally para esto).
  • La tarea no puede finalizar inmediatamente y debe seguir realizando operaciones que se verían afectadas por las interrupciones, por ejemplo, bloquear E / S (en este caso, probablemente no deberías llamar a cancel )

Entonces, ¿cuándo / por qué cancelar una tarea sin interrumpirla?


Si tiene miedo de que la interrupción de la ejecución de la tarea deje las cosas en mal estado, y simplemente desea marcarlo como cancelado para que los usuarios del Future lo sepan (por ejemplo, deben saber que las estadísticas solicitadas no se realizaron en hora).

Escribir código enhebrado que maneje las interrupciones correctamente no es para nada trivial, por lo que uno simplemente podría preferir evitarlo.

Parte de la información se puede encontrar aquí , aquí y, por supuesto, en el gran libro Programación concurrente en Java (por el tipo que originalmente escribió java.util.concurrent ).


Tengo un caso de uso que puede ser interesante para ti: tengo un único hilo que está ejecutando un conjunto de tareas programadas. Una de las tareas puede ser reprogramada por sí mismo o por otra tarea.

Para hacer esto, uso Future.cancel(false) en la copia existente en la cola, y luego programo la tarea para la nueva hora.

Si se llama a este código desde la tarea programada, la operación de cancelación será no operativa, y la tarea se programará para ejecutarse nuevamente en el futuro. Si se llama al código desde otro contexto, la próxima tarea aún no ha comenzado la ejecución, por lo que se cancelará y se reemplazará con una tarea programada para el nuevo horario.


tl; dr; Future.cancel(false) solo es útil para evitar el inicio de tareas que aún no se han iniciado.

Hay dos cosas importantes que entender sobre concurrencia y cancelación.

El primero es que en Java la cancelación es puramente cooperativa. Java señala la solicitud de cancelación haciendo que los métodos de bloqueo arrojen InterruptedExcetions y estableciendo un indicador en el subproceso. La implementación de la tarea es responsable de notar la solicitud de cancelación Y cancelarse. Brian Goetz explica la interrupción en su publicación Cómo lidiar con InterruptedException . No todas las implementaciones de tareas manejarán correctamente la interrupción.

Lo segundo que hay que señalar es que el objeto Future es un marcador de posición para que los resultados de una tarea se ejecuten en el futuro. Si no tiene muchos subprocesos en ejecución, es posible que la tarea comience a ejecutarse de inmediato, pero también es posible que todos los subprocesos ya estén siendo utilizados y la tarea tenga que esperar. El hecho de que tenga una referencia a un objeto Future no significa que la tarea correspondiente realmente haya comenzado a ejecutarse. Es como una reserva.

Tiene un objeto Future pero la tarea podría estar en uno de los siguientes estados:

  1. Esperando. Por ejemplo, podría estar en una cola de otras tareas esperando el tiempo del procesador.
  2. Corriendo.
  3. Terminado.

Si su tarea está en el primer estado "Esperando", tanto Future.cancel(true) como Future.cancel(false) marcarán el futuro como cancelado. La tarea permanece en la cola de tareas para ejecutar, pero cuando el ejecutor llega a la tarea, nota el indicador cancelado y se salta.

Si su tarea está en el tercer estado "Completado", tanto Future.cancel(true) como Future.cancel(false) devuelven falso y no hacen nada. Lo cual tiene sentido porque ya están hechos y no hay forma de deshacerlos.

El indicador mayInterruptIfRunning solo es importante si su tarea está en el segundo estado "En ejecución".

Si su tarea se está ejecutando y mayInterruptIfRunning es falso, entonces el ejecutor no hace nada y permite que la tarea se complete.

Si su tarea se está ejecutando y mayInterruptIfRunning es verdadero, el ejecutor interrumpirá la tarea. Pero recuerda lo de la cancelación cooperativa: para que la interrupción funcione, la tarea debe haberse implementado para manejar la cancelación.

Resumen:

Future.cancel(true) es apropiado cuando:

  1. El futuro representa una tarea de larga ejecución que se sabe que se implementó para manejar la interrupción.

Future.cancel(false) sería correcto:

  1. La implementación de la tarea no puede manejar la interrupción.
  2. Es desconocido si la implementación de la tarea admite la cancelación.
  3. Está dispuesto a esperar a que las tareas ya iniciadas se completen.