2016-10-24 48 views
0

我有一個基於JSP的(Java)Web應用程序。在這個應用程序中,我可以通過執行外部命令,向機器(PC)詢問他們的狀態和基於他們IP的實際操作系統。ExecutorService和OutOfMemoryError:無法使用執行程序創建新的本機線程

爲了加速請求,我想用線程同時詢問更多的機器,即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; 
} 

我的問題是,進程數/線程不斷增加,經過一段時間後,我得到了內存不足的異常。每調用一次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'是你的類中的一個靜態變量,你可以從實例方法中使用它。這是要求混亂。每次調用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。另外,您是否確認了awaitTermination函數返回true?等待終止在20秒內未完成並返回錯誤的可能性很小。新的線程池不斷得到創建,而不是舊的線程池得到GC並最終耗盡內存。

相關問題