J'ai une base d'application web (java) sur JSP. Dans cette application, je peux demander aux machines (PC) à propos de leur état et du système d'exploitation réel en fonction de leur IP en exécutant une commande externe.ExecutorService et OutOfMemoryError: impossible de créer un nouveau thread natif lors de l'utilisation de Executor
Pour accélérer la demande, j'ai pensé à demander plus de machines simultanément en utilisant des threads, c'est-à-dire ExecutorService.
L'écouteur preRenderView de la vue correspondante est défini sur cette méthode où je collecte toutes les données qui doivent être affichées. Ici, j'initialiser l'exécuteur testamentaire, qui est déclarée comme un champ de classe statique privée (private static ExecutorService executor
):
public void selectData(ComponentSystemEvent event)
{
AmtRoomMachinesListController.executor = Executors.newFixedThreadPool(20);
AmtRoomMachinesListModel amtRoomMachinesListModel = (AmtRoomMachinesListModel)getModel();
List<ListRow> listRows = fetchListRows(amtRoomMachinesListModel);
...
}
dans fetchListRow
l'exécuteur testamentaire est appelée et le appelable soumis. Ensuite, l'exécuteur est arrêté et mis fin:
private List<ListRow> fetchListRows(AmtRoomMachinesListModel amtRoomMachinesListModel)
{
...
List<ListRow> listRows = Collections.synchronizedList(new ArrayList<ListRow>());
for (Machine machine : room.getRoomPCs())
{
executor.submit(new AmtcWorker(listRows, machine, amtRoomMachinesListModel));
}
executor.shutdown();
try
{
executor.awaitTermination(20, TimeUnit.SECONDS);
}
catch (InterruptedException e)
{
throw new BootrobotException(ExceptionType.AMTC_ERROR, "command", "Waiting for thread termination", "error", e.getMessage());
}
((ThreadPoolExecutor)executor).purge();
LOGGER.info("Executor is shut down: " + executor.isShutdown());
LOGGER.info("Executor is terminated: " + executor.isTerminated());
sortListRows(listRows);
return listRows;
}
Mon problème est que le nombre de processus/threads augmente constamment et après un certain temps je reçois l'exception OutOfMemory. Chaque fois que le selectData
est appelé, le nombre de processus augmente en fonction du nombre de machines invitées. Je suis une recrue avec un thread, mais je pensais que l'exécuteur s'occuperait des threads générés en les terminant/les supprimant quand executor.shutdown() ou executor.awaitTermination ou executor.purge() est appelé.
Qu'est-ce qui me manque?
Création d'un exécuteur pour chaque demande est suspect. Il est probable que vous deviez créer un exécuteur et l'utiliser pour TOUTES les demandes. – OldCurmudgeon
Avez-vous essayé d'annuler la référence après la fin de l'exécuteur? En dehors de cela, je seconde @OldCurmudgeon. Vous devriez probablement créer un ExecutorService "global" et utiliser [InvokeAll] (https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#invokeAll-java.util.Collection -long-java.util.concurrent.TimeUnit-). – Fildor
Vous avez des instructions de journalisation dans votre code. Que montre le journal? Attendez-apparemment, votre 'executor' est une variable' static' dans votre classe que vous utilisez depuis les méthodes d'instance. C'est demander le chaos. Cette variable est écrasée chaque fois que 'selectData' est appelée, même si d'autres objets l'utilisent encore. Vous n'avez donc aucun contrôle sur l'exécuteur qui sera arrêté (ou à quelle fréquence) et qui ne s'arrêtera jamais. – Holger