Pregunta

¿Puedes ver el error? Esto arrojará un java.lang.OutOfMemoryError.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestTheads {

    public static void main(String[] args) {

        ExecutorService executorService = Executors.newFixedThreadPool(1);
        while(true) {
            executorService.submit(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                    }
                }
            });
        }
    }

}

El error es que yo llamo executorService.submit() en vez de executorService.execute(), porque submit() Devuelve un Future Objeto que estoy ignorando. Con execute(), este programa realmente se ejecutará para siempre.

Sin embargo, uno no siempre tiene el lujo de tener un execute() método, como cuando se usa un ScheduledExecutorService:

public static void main(String[] args) {
    // this will FAIL because I ignore the ScheduledFuture object
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
    while(true) {
        executorService.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                }
            }
        }, 1, 1, TimeUnit.SECONDS);
    }
}

¿Qué se supone que se supone que se debe hacer con las tareas que no devuelven nada, solo calculador?

¡Cualquier idea sería agradecida apreciada!

EDITAR: ThreadPoolExecutors purge() Parecía prometedor, pero solo purga tareas canceladas.

¿Fue útil?

Solución

los Future el objeto que se devuelve está fuertemente referenciado por el ExecutorService solo hasta que se ejecute. (En realidad es un FutureTask instancia que delegue a su Runnable.) Una vez que se haya ejecutado, se recolectará basura, porque la persona que llama no tiene referencia a ella. En otras palabras, el problema de la memoria no tiene nada que ver con el tratamiento del Future.

Si se está quedando sin memoria, es porque la cola de trabajo tiene millones de tareas en cola. Al igual que con cualquier cola, a menos que la tasa promedio de consumo exceda la tasa promedio de producción, la cola se llenará. El contenido de la cola consumen memoria.

Use una cola limitada, que efectivamente, acelere las tareas de las tareas o obtendrá más memoria.

Este código se ejecutará "para siempre":

  ExecutorService executorService = Executors.newFixedThreadPool(1);
  while(true) {
    executorService.submit(new Runnable() {
      public void run() {
        try {
          Thread.sleep(10);
        } catch (InterruptedException e) { }
      }
    });
    Thread.sleep(12);
  }

La diferencia no está en el tratamiento de los resultantes Future instancias, pero esas tareas están en cola a una velocidad a la que pueden procesarse.

Otros consejos

No son tanto los futuros que se están devolviendo su problema. El problema es que, para cada ejecutable que envíe, el servicio de ejecutor los almacenará para poder procesar en un momento posterior. Cada vez que invoca el método de envío con un ejecutable (o futuro), el servicio de ejecución lo impulsará a una cola de trabajadores. El Runnable se sentará allí hasta que un hilo pueda elegir ese corredor de la cola (la hora posterior). Si todos los hilos de los trabajadores están ocupados, el servicio de ejecutores simplemente pondrá el ejecutable a dicha cola.

Entonces, su problema es que solo tiene un hilo tratando de extraer una cola que se agrega infinitamente por otro hilo. Se agrega mucho más rápido de lo que el hilo del trabajador puede procesar cada uno ejecutable.

EDITAR: El ejemplo de código que di como los que eludió, de hecho, lanza una concepción de EXECUCIÓN DE RECHAGE, por lo que el mecanismo de aceleración tendría que ser ligeramente diferente si tuviera que elegir.

En cuanto a una mejor solución, como mencioné en mi comentario; Si espera llenar el servicio de ejecutores de tal manera que los hilos de los trabajadores no puedan mantenerse al día con la cola, puede serializar y deserializar las solicitudes a medida que entran (construyendo su propio threadpoolexecutor), pero me aseguraría de la necesidad de tal El caso es absolutamente necesario.

Tenga en cuenta después de que se haya realizado el trabajo, esos futuros serán disgustados y se recolectan basura. Entonces, si realiza un futuro por segundo y se ejecuta bajo un segundo, el futuro en sí se eliminará y no tendrá un problema de memoria. Pero si está haciendo un futuro por segundo y los hilos hacen un futuro cada 3 segundos, eso atraerá y emitirá.

Editar: Perfilé el montón del programa que está ejecutando y el problema es exactamente eso. La FuturetAk creada por el servicio de ejecutores está sentado en la cola de trabajadores hasta que el hilo del trabajador lo elija

Class Name                                                       | Shallow Heap | Retained Heap | Percentage 
------------------------------------------------------------------------------------------------------------
java.util.concurrent.ThreadPoolExecutor @ 0x78513c5a0            |          104 | 2,051,298,872 |     99.99% 
|- java.util.concurrent.LinkedBlockingQueue @ 0x785140598        |           80 | 2,051,298,216 |     99.99% 
|  |- java.util.concurrent.LinkedBlockingQueue$Node @ 0x785142dd8|           32 | 2,051,297,696 |     99.99% 
------------------------------------------------------------------------------------------------------------

El análisis del montón se enciende un poco, hay muchos nodos de Blokingqueue $ como puedes imaginar

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top