java - una - tipos mutables python
CompletableFutura, objetos mutables y visibilidad de memoria. (1)
Estoy tratando de entender cómo CompletableFuture
en Java 8 interactúa con el modelo de memoria de Java . Me parece que para la salud mental del programador, lo siguiente debería ser ideal:
- Acciones en el hilo que completa un
CompletableFuture
antes de que se ejecuten las etapas dependientes decompletaciones - Las acciones en el hilo que
registra una finalizacióncrean una etapa dependiente antes de que se ejecute la etapa dependiente definalización
Hay una nota en la documentación de java.util.concurrent que dice que:
Acciones en un hilo antes del envío de un
Runnable
a unExecutor
antes de que comience su ejecución. Del mismo modo paraCallable
s enviado a unExecutorService
.
Lo que sugeriría que la primera propiedad es verdadera, siempre que el hilo que completa el futuro ejecute la etapa dependiente de la finalización o la envíe a un Executor
. Por otro lado, después de leer la documentación de CompletableFuture, no estoy tan seguro de eso:
Las acciones suministradas para completaciones dependientes de métodos no asíncronos pueden ser realizadas por el hilo que completa el
CompletableFuture
actual, o por cualquier otro llamador de un método de finalización.
Lo que me lleva a mis preguntas:
- ¿Son las dos propiedades hipotéticas anteriores verdaderas o no?
- ¿Existe alguna documentación específica sobre la presencia o la falta de garantías de visibilidad de la memoria cuando se trabaja con
CompletableFuture
?
Apéndice:
En el camino de un ejemplo concreto, considere este código:
List<String> list1 = new ArrayList<>();
list1.add("foo");
CompletableFuture<List<String>> future =
CompletableFuture.supplyAsync(() -> {
List<String> list2 = new ArrayList<>();
list2.addAll(list1);
return list2;
});
¿Se garantiza que agregar "foo"
a la list1
sea visible para la función lambda? ¿Se garantiza que agregar list1
a list2
sea visible para las etapas dependientes del future
?
Sí, ambas hipótesis son ciertas. El motivo es que todos los métodos
*Async()
enCompletableFuture
utilizarán unjava.util.concurrent.Executor
para realizar la llamada asíncrona. Si no proporciona uno, este será el grupo común o un Ejecutor que crea un nuevo hilo para cada tarea (en caso de que restrinja el tamaño del grupo común a 0 o 1) o un Ejecutor proporcionado por el usuario. Como ya descubrió, la documentation delExecutor
dice:Acciones en un hilo antes de enviar un objeto Ejecutable a un Ejecutor antes de que comience su ejecución, tal vez en otro hilo.
Entonces, en su ejemplo, se garantiza que
"foo"
es parte delist1
en su lambda y quelist2
es visible en etapas posteriores.Esto es básicamente cubierto por la documentación del
Executor
.