examples - fork join java ejemplos
java Fork/Join aclaraciĆ³n sobre el uso de pila (3)
Leí sobre la implementación del framework Fork / Join que se introdujo en Java 7 y solo quería comprobar si entiendo cómo funciona la magia.
Como entiendo, cuando un hilo se bifurca, crea subtareas en su cola (que otro hilo puede o no robar). Cuando el hilo intenta "unirse", en realidad comprueba su cola para las tareas existentes y luego las realiza de forma recursiva, lo que significa que para cualquier operación de "combinación": se agregarán 2 marcos a la pila de llamadas de hilo (una para la unión y otra para para la nueva invocación de tarea tomada).
Como sé que la JVM no admite la optimización de llamadas de cola (que puede servir en esta situación para eliminar el marco de la pila del método de unión), creo que al realizar una operación complicada con muchas bifurcaciones y uniones, un subproceso puede StackOverflowError
un StackOverflowError
.
¿Tengo razón o encontraron alguna manera genial de prevenirlo?
EDITAR
Aquí hay un escenario para ayudar a aclarar la pregunta: Diga (por simplicidad) que solo tenemos un hilo en el grupo de forkjoin. En algún momento, el hilo se bifurca y luego se une. Mientras que en el método de unión, el hilo descubre que puede realizar la tarea bifurcada (como se encuentra en su cola), por lo que invoca la siguiente tarea. Esta tarea, a su vez, bifurca y luego llama a unirse, así que al ejecutar el método de unión, el hilo encontrará la tarea bifurcada en su cola (como antes) y la invocará. en esa etapa, la pila de llamadas contendrá al menos los marcos para dos uniones y dos tareas.
Como se puede ver, el marco de unión de fork se transforma en una simple recursión. Debido a que java no admite la optimización de la llamada de cola, cada recursión en java puede causar StackOverflowError
si se profundiza lo suficiente.
Mi pregunta es: ¿el implementador del marco de fork / join encontró alguna manera interesante de evitar esta situación?
En general, cada nueva tarea empujada en la pila es la mitad del tamaño de la anterior. Así que la cantidad de trabajo crece exponencialmente con el tamaño de pila. Incluso con una pila pequeña, podrás encajar en el trabajo más que suficiente para mantenerte ocupado durante algún tiempo.
Espero que te entienda de la manera correcta.
Hay una cola interna en forkjoinpool que mantiene las tareas que desea ejecutar, por lo que no se puede producir un desbordamiento de pila, pero debe prepararse para una alta utilización de la memoria.
Un lugar muy interesante para el método de bifurcación es ForkJoinWorkerThread.pushTask con uso inseguro de objetos, por lo que debe prestar atención a que la matriz se usa para almacenar tareas.
EDITAR: Primero y simple: cuando se encuentra en la parte superior de la cola, simplemente no se pulsa y se ejecuta, y se devuelve el retorno. (forkjointask.java:353)
Se usa un enfoque diferente cuando tiene dependencias, en este caso el control se devuelve a WorkerThread, quien es el responsable de detectar las cadenas y ejecutarlas. Por primera vez, el trabajador verifica la cola local en busca de tareas no deseadas, y si no realiza tales tareas, ejecuta el trabajo aprobado y devuelve el resultado; de lo contrario, pasa al siguiente caso. Lo que está ayudando a los ladrones varias veces. Nada podría ayudar ... los reintentos que en el primer paso son iguales a MAX_HELP es cero ahora: el control se pasa a la agrupación, que realiza varias comprobaciones y ejecuta tryAwaitDone. Y en este método se invoca la espera para esperar la finalización de la tarea.
Esto significaría que el grupo de unión de bifurcaciones terminaría en varios pasos, intentando optimizar la velocidad y el tiempo evitando las llamadas a la espera. Sin embargo, podría terminar en espera, entonces esto significaría un proceso de sincronización para comenzar, lo cual es muy costoso.
Por lo tanto, no hay uniones subsiguientes para la profundidad inifinita, pero los intentos lógicos de ejecutar tareas lo más rápido posible.
Lamentablemente no hay nada mágico sucediendo en términos de la pila recursiva de hilos. Si su tarea inicial se divide / divide y no tiene un punto de resolución razonable, se encontrará con Errors.
Probablemente pueda comprender por qué el tutorial de JavaDoc divide cada subtarea a la mitad.