У меня есть (java) база веб-приложений на JSP. В этом приложении я могу попросить компьютеры (ПК) об их состоянии и фактической операционной системе на основе их IP, выполнив внешнюю команду.ExecutorService и OutOfMemoryError: не удается создать новый собственный поток при использовании Executor
Чтобы ускорить запрос, я подумал спросить больше машин одновременно с использованием потоков, то есть ExecutorService.
Этот прослушиватель PreRenderView соответствует этому методу, где я собираю все данные, которые должны быть показаны. Здесь я инициализировать исполнитель, который объявлен как частный статическое поле класса (private static ExecutorService executor
):
public void selectData(ComponentSystemEvent event)
{
AmtRoomMachinesListController.executor = Executors.newFixedThreadPool(20);
AmtRoomMachinesListModel amtRoomMachinesListModel = (AmtRoomMachinesListModel)getModel();
List<ListRow> listRows = fetchListRows(amtRoomMachinesListModel);
...
}
fetchListRow
в исполнитель называется и вызываемым представлены. Затем исполнитель выключается и прекращается:
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;
}
Моя проблема заключается в том, что количество процессов/потоков постоянно увеличивается, и через некоторое время я получаю OutOfMemory исключение. Каждый раз, когда вызывается selectData
, количество процессов увеличивается на количество запрашиваемых машин.
Я новичок с потоками, но я думал, что исполнитель позаботится о сгенерированных потоках, прекратив/убивая их, когда вызывается функция executor.shutdown() или executor.awaitTermination или executor.purge().
Что мне не хватает?
Создание нового исполнителя для каждого запроса подозреваемого. Вероятно, вы должны создать одного исполнителя и использовать его для ВСЕХ запросов. – OldCurmudgeon
Вы пытались обнулить ссылку после выполнения Исполнителем? Вне этого я второй @OldCurmudgeon. Вероятно, вы должны создать один «глобальный» ExecutorService и использовать [InvokeAll] (https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#invokeAll-java.util.Collection -длинный-java.util.concurrent.TimeUnit-). – Fildor
У вас есть записи в вашем коде. Что показывает журнал? Подождите, видимо, ваш 'executor' является переменной' static' в вашем классе, которую вы используете из методов экземпляра. Это требует хаоса. Эта переменная перезаписывается каждый раз, когда вызывается 'selectData', даже если другой объект все еще использует его. Таким образом, вы не можете контролировать, какой исполнитель будет отключен (или часто) и который никогда не будет отключен. – Holger