滥用ThreadPoolExecutor - OOM错误

时间:2016-09-12 18:38:58

标签: java

我正在无限制的流中读取 SQS 中的文件。当我读取每个文件时,我想将其提交到第二个队列进行处理。我可以同时处理几个文件,所以我将它们放入线程中,并希望在所有线程都在使用时阻止从队列中进一步读取。

为此,我使用了这个:

ExecutorService executorService =
   new ThreadPoolExecutor(
       maxThreads, // core thread pool size
       maxThreads, // maximum thread pool size
       1, // time to wait before resizing pool
       TimeUnit.MINUTES,
       new ArrayBlockingQueue<Runnable>(maxThreads, true),
       new ThreadPoolExecutor.CallerRunsPolicy());

maxThreads = 2

文件以十个为单位进行读取并按原样处理:

for (Message msg : resp.getMessages()) {
    Gson g = new Gson();

    MessageBody messageBody = g.fromJson(msg.getBody(), MessageBody.class);
    MessageRecords messageRecords = g.fromJson(messageBody.getMessage(), MessageRecords.class);

    List<MessageRecords.Record> records = messageRecords.getRecords();

    executorService.submit(new Runnable() {
        @Override
        public void run() {
        ... do some work based on file type
        }
    });

观察线程数我看到它一直稳步攀升,直到系统内存不足,用无法创建本机线程异常关闭作业。在此之后,VM(AWS)不会接受SSH登录,直到它被停止/重新启动。

似乎必须有一个给定线程被释放/清理的步骤,但我没有看到它应该发生在哪里。

我做错了什么?

编辑:

  • 是的,run()完成并退出
  • 没有其他任何东西与这些线程交互。 run()方法获取文件,查看类型并根据类型调用fn()。函数解析文件并返回。然后run()完成了。

1 个答案:

答案 0 :(得分:0)

问题在于我使用ThreadPoolExecutor。特别是它在应用程序进程中出现(s / ed)的位置。我通过一个SQS消息块为每个循环创建一个新的线程池,然后不关闭它。将此创建移到循环中并重复使用相同的块可以解决问题。

所以 - 一个大毛茸茸的UFU。