ExecutorService and OutOfMemoryError: unable to create new native thread while using Executor

ExecutorService and OutOfMemoryError: unable to create new native thread while using Executor

我有一个基于 JSP 的 (java) 网络应用程序。在这个应用程序中,我可以通过执行外部命令,根据它们的 IP 向机器 (PC) 询问它们的状态和实际操作系统。

为了加速请求,我想同时使用线程请求更多机器,即 ExecutorService。

相应View的preRenderView监听器设置为这个方法,我收集所有必须显示的数据。这里我初始化了executor,声明为private static class字段(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;
}

我的问题是 processes/threads 的数量不断增加,一段时间后我得到 OutOfMemory 异常。每调用一次selectData,进程数就会增加提示的机器数。

我是线程方面的菜鸟,但我认为执行程序会在 executor.shutdown() 或 executor.awaitTermination 或 [= 时通过 terminating/killing 处理生成的线程33=]() 被调用。

我错过了什么?

使用一个线程池。另外,您是否确认 awaitTermination 函数返回 true?极有可能 awaitTermination 没有在 20 秒内完成并且 returns false。新线程池不断创建,而旧线程池没有被 GC 处理并最终 运行 内存不足。

我的建议是只创建一个线程池。线程池旨在管理您的线程。如果你每次调用一个方法都创建一个线程池,那么基本上它和每次调用一个方法都创建线程一样糟糕,但如果你仍然坚持创建多个线程池那么你为什么不试试这个相反

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;
}

刚刚本地化了执行器