2009-11-05 4 views
25

ThreadPoolExecutor에 대한 간단한 질문입니다. 다음과 같은 상황이 있습니다. 큐에서 개체를 소비하고 적절한 작업자 작업을 만들어 ThreadPoolExecutor에 제출해야합니다. 이것은 아주 간단합니다. 그러나 종료 시나리오에서 많은 작업자가 실행 대기열에있을 수 있습니다. 이러한 작업 중 하나가 한 시간 동안 실행될 수 있기 때문에 응용 프로그램을 상대적으로 빠르게 종료하려면 ThreadPoolExecutor에서 대기중인 작업을 모두 삭제하고 이미 처리중인 작업은 정상적으로 완료되어야합니다.ThreadPoolExecutor의 대기중인 작업을 모두 제거

ThreadPoolExecutor 설명서에는 remove() 메서드가 있지만 특정 작업 만 제거 할 수 있습니다. purge()은 이미 취소 된 향후 작업에만 적용됩니다. 내 아이디어는 모든 대기열에있는 작업을 보유하고있는 대기열을 지우는 것이 었습니다. ThreadPoolExecutor에이 내부 큐에 액세스 할 수 있지만, 문서 상태 :

방법 getQueue()를 디버깅 모니터링 목적 작업 큐에 액세스 할 수있다. 이 방법을 다른 목적으로 사용하면 은 강력하게 입니다.

그래서이 대기열을 잡고 지우는 것은 옵션이 아닙니다. 또한, 문서의이 조각은 말한다 :

두 제공된 방법, 제거 (java.lang.Runnable의)와 퍼지를() 의 큰 숫자가 취소 될 작업을 대기 할 때 스토리지에 개척을 돕기 위해 사용할 수있는 .

어떻게? 물론, 나는 executor에게 제출 한 모든 task의리스트를 유지할 수있다. 그리고 shutdown case에서 모든 항목을 반복하고 remove() 메소드로 ThreadPoolExecutor에서 제거한다 ... 그러나 ... 기억의 낭비와이 목록을 유지하는 번거 로움. (예 : 이미 실행 된 작업 제거)

나는 어떤 힌트 또는 해결책을 주셔서 감사합니다!

답변

9

ExecutorService를 래핑하는 것이 고려 되었습니까? 만들기

CleanShutdownExecutorService implements Executor 

그 대표가 모든 다른 집행자를 호출하지만, 자신의 목록에 선물을 유지합니다. 그런 다음 CleanShutdownExecutorService는 shutdown()을 호출 한 cancelRemainingTasks() 메서드를 가질 수 있으며 해당 목록의 모든 Futures에 대해 cancel (false)를 호출합니다.

+0

이것은 가장 깨끗한 접근 방법 일 수 있으므로이 대답을 수락합니다. :-) 나는 이미 그와 같은 것이 있기를 바랐다. :-) – Malax

4

ExecutorService.shutdown()이 충분하지 않고 ExecutorService.shutdownNow()이 너무 많은 작업을하고 있습니다. 제출 한 모든 작업을 기억하고 수동으로 (또는 전에) shutdown()으로 전화를 걸어 제거하십시오.

+0

"이전에 제출 된 작업이 실행되지만 새로운 작업은 수락되지 않는 정상적인 종료를 시작합니다." 더 이상 실행해서는 안되는 몇 가지 작업을 제출했습니다. 그러나 ** 실행 ** 작업은 끝나서는 안됩니다. – Malax

+0

내 의견이 더 이상 유효하지 않게 답변을 편집했습니다. 그럼에도 불구하고 shutdownNow() 문서에는 "적극적으로 실행중인 모든 작업을 중지하려고 시도합니다." 그게 내가 원하는 것 아니야. :) – Malax

+0

오, 맞아, 나는 그 문장의 절반을 겹쳐 썼다. 글쎄, 당신의 유일한 옵션은 모든 제출 된'Runnable'을 기억하고 수동으로 제거하는 것입니다. 그에 따라 편집하겠습니다. – Bombe

1

Bombe의 답변은 원하는 내용입니다. shutdownNow()누크를 사용하여 모든 것을 중지하고 접근 방식으로 포장합니다. 이것은 당신이 사용하고있는 ThreadPoolExecutor의 구현을 서브 클래 싱 (subclassing)하기에는 당신이 할 수있는 최선의 방법입니다. interrupt()이 shutdownNow의 (에 의해 그들에 호출 될 때 (을 통해 진짜 생각을하거나 테스트) 작동 할 수 있습니다

0

미친 부정한 솔루션은 종료를 거부 할 경우에만 일부 글로벌 값을 설정하여 WorkerTasks의 interrupt()을 덮어 쓸 것).

그렇다면 shutdownNow()을 사용할 수 있습니까?

0

스레드 풀을 종료, getQueue에게 각각의 결과를 개별 Runnable로 알리고 remove 메소드를 사용하여 각 Runnable을 제거하십시오. 대기열 유형에 따라 반환 값에 따라 조기에 제거 작업을 중단 할 수 있습니다.

기본적으로이 방법은 큐를 가져 와서 지우는 것이며, 작동하는 방법을 통해서만 지울 수 있습니다. 수동으로 모든 제출을 기억하는 대신 스레드 풀이 이미 모든 제출을 기억해야한다는 사실을 사용합니다. 그러나 라이브 뷰라고 생각할 때 큐의 방어 복사본을 만들어야 할 수도 있습니다. 따라서 라이브 뷰를 반복/수행 할 때 제거하면 동시 수정 예외가 발생할 수 있습니다.

12

나는 오래 실행중인 스레드로 작업하는 데 익숙합니다. 종료시이 작업을 수행합니다.

BlockingQueue<Runnable> queue = threadPool.getQueue(); 
List<Runnable> list = new ArrayList<Runnable>(); 
int tasks = queue.drainTo(list); 

목록이 파일로 저장됩니다. 시작할 때 목록이 풀에 다시 추가되므로 작업이 손실되지 않습니다.

+2

내 질문에 멋진 추가. :-) 나는 내 작업의 지속성이 문제가되지 않습니다. 그러나 당신의 추가는 다른 사람들에게 도움이 될 수 있습니다. :) – Malax

+0

나는 이것이 올바른 접근법인지 모르겠습니다. shutdown()을 사용하여 종료하면 모든 것이 종료 될 때까지 기다립니다 (대기중인 작업도 포함). shutdownNow()를 사용하면 대기중인 작업의 목록이 이미 반환됩니다. 그냥 참고로. – Whimusical

0

종료 후 awaitTermination(long timeout, TimeUnit unit)이 작동하지 않습니까?

executor.shutdown(); 당신이 오래된 질문이지만, 경우에이 다른 사람을 도움이 allowCoreThreadTimeOut(true);

1

executor.awaitTermination (60, TimeUnit.SECONDS) : 당신이 종료를 호출 할 때) (휘발성 부울을 설정할 수 있습니다, 실제로 시작하기 전에 부울이 설정되면 제출 된 각 태스크가 종료되도록하십시오. 이것은 진정으로 완료되기 시작한 작업을 허용하지만 대기중인 작업이 실제 작업을 시작하지 못하도록합니다.

+0

답을 개발하고 실제로 OP에 동의하는지 분명히해야합니다. –

3

을 시도 할 수 있습니다

관련 문제