ExecutorService並列処理タスクの作成によりメモリ不足

2021 ワード

ExecutorServiceで作成したスレッドプールを使用してタスクを並列に処理することで、合計待ち時間(合計待ち時間は、最も多くの時間を費やしたタスクの時間と同じ)を節約できます.ただし、スレッドプールは自動的に解放されません.したがって、スレッドプールを1回作成した後に繰り返し使用するか、使用が完了するたびに明示的に解放されます.そうでないと、メモリが最終的に使用されなくなります.
問題:
Executorsを使用してスレッドプールの一括並列処理タスク(外部インタフェースの要求など)を作成し、しばらくするとjvmがOutOfMemoryエラーを報告し、プロセスが死んでしまいます.
jstackでスレッド数を観察すると、いくつかのタイプのスレッドが成長しています.
jstack | grep "waiting on condition"| wc -l
jstack | grep "waiting on condition"| grep pool |wc -l
問題コード(batchProcessは絶えず呼び出されます):
private void batchProcess(List idList) throws Exception {
   ExecutorService executorService = Executors.newFixedThreadPool(idList.size());
   List taskList = new ArrayList<>();
   for(Integer id : idList){
      taskList.add(new AreaThread(id));
   }

   List> futureList = executorService.invokeAll(taskList);

   List resultList = new ArrayList<>();
   for(Future future : futureList){
      Integer result = future.get();
      logger.debug("result={}", result);
      resultList.add(result);
   }
}

理由:executorServiceは明示的に閉じられず、スレッドプールが作成された後も新しいタスクを待っていたため、蓄積が多くなりました.
修正後のコード:
private void batchProcess(List idList) throws Exception {
   ExecutorService executorService = Executors.newFixedThreadPool(idList.size());
   List taskList = new ArrayList<>();
   for(Integer id : idList){
      taskList.add(new AreaThread(id));
   }

   List> futureList = executorService.invokeAll(taskList);

   List resultList = new ArrayList<>();
   for(Future future : futureList){
      Integer result = future.get();
      logger.debug("result={}", result);
      resultList.add(result);
   }

   executorService.shutdown(); //   shutdown,         
}

または:共通の
executorServiceは、すべての一括タスクで使用されるように、常に存在させます.