2016-10-24 2 views
0

У меня есть (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().

Что мне не хватает?

+3

Создание нового исполнителя для каждого запроса подозреваемого. Вероятно, вы должны создать одного исполнителя и использовать его для ВСЕХ запросов. – OldCurmudgeon

+0

Вы пытались обнулить ссылку после выполнения Исполнителем? Вне этого я второй @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

+1

У вас есть записи в вашем коде. Что показывает журнал? Подождите, видимо, ваш 'executor' является переменной' static' в вашем классе, которую вы используете из методов экземпляра. Это требует хаоса. Эта переменная перезаписывается каждый раз, когда вызывается 'selectData', даже если другой объект все еще использует его. Таким образом, вы не можете контролировать, какой исполнитель будет отключен (или часто) и который никогда не будет отключен. – Holger

ответ

1

Мое предложение состоит в том, чтобы создать только один пул потоков. Пул потоков предназначен для управления вашими потоками. Если вы создаете пул потоков каждый раз, когда вызывается метод, то в основном это так же хуже, как создание потока каждый раз, когда вы вызываете метод, но если вы все еще настаивали на создании более одного пула потоков, то почему бы вам не попробовать это вместо

private List<ListRow> fetchListRows(AmtRoomMachinesListModel amtRoomMachinesListModel) 
{ 
    ExecutorService executor = Executors.newFixedThreadPool(20); 
... 
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; 
} 

просто локализовали исполнителя

1

Используйте один ThreadPool. Кроме того, подтвердили ли вы, что функция ожидания перестает возвращаться? Это отдаленная возможность, что ожидание завершения не завершается в течение 20 секунд и возвращает false. Новые пулы потоков продолжают создаваться без старых, получающих GCed, и в конечном итоге заканчиваются из памяти.

 Смежные вопросы

  • Нет связанных вопросов^_^