2016-10-24 3 views
0

JSP (Java) 웹 응용 프로그램을 기반으로합니다. 이 응용 프로그램에서는 컴퓨터 (PC)에 외부 명령을 실행하여 IP 상태에 따라 상태 및 실제 운영 체제를 요청할 수 있습니다.ExecutorService 및 OutOfMemoryError : Executor를 사용하는 동안 새로운 네이티브 스레드를 만들 수 없습니다.

요청을 가속화하기 위해 더 많은 기계에 스레드 (예 : ExecutorService)를 동시에 요청하는 것으로 생각했습니다.

해당 View의 preRenderView 수신기는 표시해야하는 모든 데이터를 수집하는이 메서드로 설정됩니다. 여기에 개인 정적 클래스 필드 (private static ExecutorService executor)로 선언 집행자를 초기화 :

집행자가 호출 및 제출 호출됩니다 fetchListRow
public void selectData(ComponentSystemEvent event) 
{ 
    AmtRoomMachinesListController.executor = Executors.newFixedThreadPool(20); 

    AmtRoomMachinesListModel amtRoomMachinesListModel = (AmtRoomMachinesListModel)getModel(); 

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

. 그런 다음 실행자는 종료하고 종료 :

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()가 호출 될 때 executor가 생성 된 스레드를 종료/종료하여 처리한다고 생각했습니다.

무엇이 누락 되었습니까?

+3

현지화 의심이다. 하나의 실행 프로그램을 작성하여 모든 요청에 ​​사용하는 것이 좋습니다. – OldCurmudgeon

+0

실행자가 완료된 후에 참조를 null로 시도 했습니까? 그 외에, 나는 두 번째 @OldCurmudgeon. 하나의 "전역"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

내 제안은 하나의 스레드 풀만 생성하는 것입니다. 스레드 풀은 스레드를 관리하기위한 것입니다. 메소드가 호출 될 때마다 스레드 풀을 작성하는 경우, 기본적으로 메소드를 호출 할 때마다 스레드를 작성하는 것보다 나쁘지 만, 둘 이상의 스레드 풀을 작성해야한다고 주장하는 경우,이 메소드를 시도하십시오. 대신

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를 반환하는지 확인 했습니까? awaitTermination이 20 초 내에 완료되지 않고 false를 반환하는 원격 가능성이 있습니다. 새로운 쓰레드 풀은 GCed를 얻지 않고 메모리를 모두 소모하지 않고 계속 생성됩니다.