2016-10-24 14 views
0

JSP上に(Java)Webアプリケーションベースがあります。このアプリケーションでは、外部コマンドを実行することによって、IPに基づいて状態(state)と実際のオペレーティングシステムについてマシン(PC)に問い合わせることができます。ExecutorServiceとOutOfMemoryError:Executorを使用している間に新しいネイティブスレッドを作成できません

リクエストを高速化するために、スレッドを使用して複数のマシン、つまりExecutorServiceを同時に要求すると考えました。

対応するViewのpreRenderViewリスナーがこのメソッドに設定され、ここで表示する必要があるすべてのデータを収集します。 executorが呼び出されると、呼び出し可能が提出されfetchListRow

public void selectData(ComponentSystemEvent event) 
{ 
    AmtRoomMachinesListController.executor = Executors.newFixedThreadPool(20); 

    AmtRoomMachinesListModel amtRoomMachinesListModel = (AmtRoomMachinesListModel)getModel(); 

    List<ListRow> listRows = fetchListRows(amtRoomMachinesListModel); 
... 
} 

:ここで私は、プライベート静的クラスフィールド(private static ExecutorService executor)として宣言されたexecutorを、初期化します。その後、エグゼキュータは、シャットダウンして終了します:

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

をローカライズされた容疑者です。 1つのエグゼキュータを作成し、それをすべての要求に使用する必要があります。 – OldCurmudgeon

+0

実行者の実行後に参照をnullにしてみましたか?それ以外では、私は2番目@OldCurmudgeon。おそらく、1つの「グローバル」ExecutorServiceを作成し、[InvokeAll](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#invokeAll-java.util.Collection)を使用する必要があります。 -long-java.util.concurrent.TimeUnit-)。 – Fildor

+1

コードにロギングステートメントがあります。ログには何が表示されますか?ちょっと待ってください。あなたの 'executor'はインスタンスメソッドから使​​うクラスの' static'変数です。それは混乱を求めています。その変数は、 'selectData'が呼び出されるたびに上書きされます。他のオブジェクトがまだそれを使用していても変わりません。したがって、どのエグゼキュータがシャットダウン(またはどのくらいの頻度)されるのか、またどのエグゼクティブがシャットダウンされるのかは制御できません。 – Holger

答えて

1

私の提案は、スレッドプールを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

1つのThreadPoolを使用します。また、awaitTermination関数がtrueを返すことを確認しましたか? awaitTerminationが20秒以内に完了せず、falseを返す可能性があります。新しいスレッドプールは、古いものがGCedになっていなくても作成され続け、最終的にはメモリ不足になります。

関連する問題