ExecutorService에서 shutdown ()을 호출하는 이유


84

나는 지난 몇 시간에 대해 상당히 읽고 있었다, 나는 단순히 어떤 이유 (볼 수없는 유효한 전화에 이유) shutdown()ExecutorService우리는 엄청난 응용 프로그램을하지 않는 한, 어떤 상점, 수십 사용되지 않는 다른 실행 프로그램 서비스의 수십 오랫동안.

(내가 모은 것에서) 셧다운이하는 유일한 일은 일단 정상 쓰레드가하는 일을하는 것입니다. 일반 Thread가 Runnable (또는 Callable)의 run 메소드를 완료하면 Garbage Collection으로 전달되어 수집됩니다. Executor Service를 사용하면 스레드가 단순히 보류 상태가되고 가비지 수집을 위해 틱되지 않습니다. 이를 위해 종료가 필요합니다.

내 질문으로 돌아갑니다. ExecutorService자주 또는 일부 작업을 제출 한 직후 에 shutdown을 호출 할 이유가 있습니까? 나는 누군가가 그것을하고있는 사건을 남겨두고 awaitTermination()이것이 검증 된 직후에 전화를 걸고 싶습니다 . 일단 ExecutorService그렇게하면 똑같은 일을하기 위해 새로운 것을 다시 만들어야합니다 . ExecutorService스레드를 재사용 하는 전체 아이디어가 아닙니까? 그렇다면 왜 ExecutorService그렇게 빨리 파괴 합니까?

단순히 생성 ExecutorService(또는 필요한 수에 따라 결합) 한 다음 애플리케이션 실행 중에 작업이 수행되면 작업을 전달한 다음 애플리케이션 종료 또는 다른 중요한 단계에서 해당 실행기를 종료하는 것이 합리적인 방법입니까? ?

ExecutorServices를 사용하여 많은 비동기 코드를 작성하는 숙련 된 코더의 답변을 원합니다.

두 번째 질문, 안드로이드 플랫폼에 대한 조금 더 작은 문제입니다. 매번 실행 프로그램을 종료하는 것이 최선의 생각이 아니라고 말하고 Android에서 프로그래밍하는 경우 다른 이벤트를 처리 할 때 이러한 종료를 처리하는 방법 (구체적으로-실행할 때)을 알려주세요. 응용 프로그램 수명주기.

CommonsWare 의견 때문에 게시물을 중립적으로 만들었습니다. 나는 그것에 대해 죽음에 대해 논쟁하는 데 정말로 관심이 없으며 그것이 거기로 이끄는 것처럼 보입니다. 경험을 공유 할 의향이있는 경우 경험이 풍부한 개발자에게 여기서 요청한 내용에 대해서만 관심이 있습니다. 감사.


3
"작업을 제출하거나 실행 한 직후에 shutdown () 호출이 항상 발생하는 샘플 코드를 여러 번 봅니다."-귀하의 주장에 대한 증거를 제공하기 위해 하이퍼 링크를 자유롭게 사용하십시오. 개인적으로 나는 당신이 말한 것을 수행하는 "샘플 코드"를 본 적이 없습니다. 당신이 무언가를 잘못 해석하고있을 가능성이 있으며, 우리는 당신이 조사하고있는 "샘플 코드"를 알고있는 경우에만 당신에게 지적 할 수 있습니다.
CommonsWare 2013

4
안녕 CommonsWare. 우선, 나는 당신의 공격적인 어조가 나를 향한 것을 보았습니다. 나는 사람들을 부정적인 방식으로 초상화하려고하지 않았습니다. 귀하의 인용문은 주로 Thinking In Java IV 에디션, 멀티 태스킹 부분에 대해 이야기했습니다. Bruce Eckel의 예에서 많은 사례를 찾을 수 있습니다. 대부분 간단하지만 Bruce가 저에게주는 인상이 셧다운을 자주 사용한다는 인상은 결코 적지 않습니다. 어쨌든 당신은 내 게시물의 주요 부분이 아닌 것에 집중했습니다. 나는 정말로 그것에 대해 논쟁하고 싶지 않기 때문에 그 부분을 제거했습니다.
Lucas

1
Hay @CommonsWare in Thinking in Java book by Bruce Eckel .. in concurrency / Executor page 804 Fourth Edition, 그는 항상 간단한 앱에서 작업을 제출하거나 실행 한 직후에 shutdown () 메서드를 사용하여 루카스가 말한대로 Executor의 작동 방식을 설명합니다
오류

2
나는 이것이 오래된 게시물이라는 것을 알고 있지만 OP의 질문은 여전히 ​​유효하고 유효하다고 생각합니다. 또한 "execut () 직후 shutdown () 호출이있는"많은 샘플 코드를 보았습니다. tutorials.jenkov.com/java-util-concurrent/executorservice.html (당신이 "자바 ExecutorService를 예를 들어"구글 때 온다 첫번째 튜토리얼)
baekacaek

감사합니다.이 "샘플 코드"에서 제기 한 것과 동일한 질문이있었습니다. journaldev.com/2340/…
Gregordy

답변:


57

shutdown()메서드는 한 가지 작업을 수행합니다. 클라이언트가 실행기 서비스에 더 많은 작업을 보내지 못하도록합니다. 즉, 다른 작업을 수행하지 않는 한 모든 기존 작업이 계속 실행되어 완료됩니다. 예를 들어 ScheduledExecutorService의 경우와 같이 예약 된 작업의 경우에도 마찬가지입니다. 예약 된 작업의 새 인스턴스가 실행되지 않습니다. 이는 다양한 시나리오에서 유용 할 수 있습니다.

N 개의 작업을 실행하는 실행기 서비스가있는 콘솔 애플리케이션이 있다고 가정 해 보겠습니다. 사용자가 CTRL-C를 누르면 애플리케이션이 정상적으로 종료 될 것으로 예상합니다. 우아하게 의미하는 것은 무엇입니까? 응용 프로그램이 실행기 서비스에 더 많은 작업을 제출하지 못하도록하고 동시에 기존 N 작업이 완료 될 때까지 기다리기를 원할 수 있습니다. 마지막 수단으로 종료 후크를 사용하여이를 수행 할 수 있습니다.

final ExecutorService service = ... // get it somewhere

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Performing some shutdown cleanup...");
        service.shutdown();
        while (true) {
            try {
                System.out.println("Waiting for the service to terminate...");
                if (service.awaitTermination(5, TimeUnit.SECONDS)) {
                    break;
                }
            } catch (InterruptedException e) {
            }
        }
        System.out.println("Done cleaning");
    }
}));

이 후크는 서비스를 종료하여 애플리케이션이 새 작업을 제출하지 못하도록하고 JVM을 종료하기 전에 모든 기존 작업이 완료 될 때까지 기다립니다. await 종료는 5 초 동안 차단되며 서비스가 종료되면 true를 반환합니다. 이는 서비스가 결국 종료되도록 루프에서 수행됩니다. InterruptedException은 매번 삼켜집니다. 이는 애플리케이션 전체에서 재사용되는 실행기 서비스를 종료하는 가장 좋은 방법입니다.

이 코드는 완벽하지 않습니다. 작업이 결국 종료 될 것이라고 절대적으로 확신하지 않는 한, 주어진 시간 초과를 기다렸다가 종료하고 실행중인 스레드를 포기할 수 있습니다. 이 경우 shutdownNow()실행중인 스레드를 중단하려는 마지막 시도에서 시간 초과 후에 호출 하는 shutdownNow()것이 좋습니다 ( 실행 대기중인 작업 목록도 제공합니다). 작업이 중단에 응답하도록 설계된 경우 제대로 작동합니다.

또 다른 흥미로운 시나리오는 정기적 인 작업을 수행하는 ScheduledExecutorService가있는 경우입니다. 주기적인 작업 체인을 중지하는 유일한 방법은를 호출하는 것 shutdown()입니다.

편집 : 위의 일반적인 경우와 같이 종료 후크를 사용하지 않는 것이 좋습니다. 오류가 발생하기 쉬우 며 최후의 수단이어야합니다. 또한 등록 된 종료 후크가 많은 경우 실행되는 순서가 정의되지 않아 바람직하지 않을 수 있습니다. 차라리 응용 프로그램이 명시 적 shutdown()으로 InterruptedException.


늦게 답변 해주셔서 죄송합니다. 그리고 그 btw에 감사드립니다. 예, 저는 Executor의 작동 방식을 알고 있으며 제 질문에서 설명하려고했습니다. 종료는 사용자가 말한대로 수행하며 가비지 수집기가 이러한 죽은 스레드를 수집하고 실제로 ExecutorService 인스턴스를 수집 할 수 있도록합니다. 내 질문은 구체적이었습니다. ExecutorService에서 무엇이든 제출 / 실행 한 직후에 항상 "shutdown ()"을 호출 할 이유가 있습니까? 질문의 두 번째 부분은 엄격하게 Android 아키텍처와 관련이 있습니다. 이전에 대한 대답이 '아니요'인 경우 및 중에 종료를 호출 할시기입니다. 수명주기.
Lucas

3
항상 shutdown ()을 호출 할 이유가 없습니다. 실제로 실행기 서비스를 다시 사용하지 못하게하므로 절대적으로 잘못된 작업 일 수 있습니다. 서비스의 수명주기가 끝날 때이를 호출하는 이유는 눈치 채셨 듯이 스레드가 마침내 가비지 수집 될 수 있기 때문입니다. 그렇지 않으면 해당 스레드가 유휴 상태 인 경우에도 JVM을 활성 상태로 유지합니다.
Giovanni Botta

"항상 shutdown ()을 호출 할 이유가 없습니다. 실제로 실행 프로그램 서비스를 다시 사용하지 못하게 할 수 있으므로 절대적으로 잘못된 작업 일 수 있습니다." 그것은 정확히 나의 추론이고, 원래 질문에서 나온 나의 딜레마입니다. 다시 말해서 질문은 Android 수명주기에서 언제 ExecutiveService를 종료해야합니까?
Lucas

2
저는 Android 경험이 없지만 JVM이 마침내 종료되도록 애플리케이션이 종료 될 때 종료해야한다고 생각합니다.
Giovanni Botta

3
내가 참조. 캐시 된 스레드 풀 을 사용하고 shutdown()불필요 할 때 리소스를 낭비하지 않도록 절대 호출 하지 않는 것이 좋습니다. 응용 프로그램이 종료되면 풀의 스레드는 결국 가비지 수집됩니다 (기본적으로 60 초 동안 유휴 상태가 된 후). 풀을 제한하거나 다른 스레드 수명을 원하는 경우 ThreadPoolExecutor직접 만들 수 있습니다.
Giovanni Botta

13

ExecutorService가 스레드를 재사용하는 전체 아이디어가 아닙니까? 그렇다면 왜 그렇게 빨리 ExecutorService를 파괴할까요?

예. ExecutorService자주 파괴하고 재생성해서는 안됩니다 . ExecutorService필요할 때 (주로 시작시) 초기화 하고 완료 될 때까지 활성 상태로 유지합니다.

단순히 ExecutorService (또는 필요한 수에 따라 몇 개)를 생성 한 다음 응용 프로그램 실행 중에 작업이 수행되면 작업을 전달한 다음 응용 프로그램 종료 또는 다른 중요한 단계에서 해당 작업을 종료하는 것이 합리적이지 않습니까? 집행자?

예. ExecutorService애플리케이션 종료 등과 같은 중요한 단계 에서 종료 하는 것이 합리적입니다 .

두 번째 질문, 안드로이드 플랫폼에 대한 조금 더 작은 문제입니다. 여러분 중 일부는 매번 실행기를 종료하는 것이 최선의 생각이 아니라고 말하고 Android에서 프로그래밍하는 경우 응용 프로그램의 다른 이벤트를 처리 할 때 이러한 종료를 처리하는 방법 (구체적으로는 실행할 때)을 알려주세요. 수명주기.

ExecutorService애플리케이션의 여러 활동에서 공유 된다고 가정하십시오 . 각 활동은 서로 다른 시간 간격으로 일시 중지 / 재개되며 여전히 ExecutorService애플리케이션 당 하나씩 필요 합니다.

ExecutorService활동 라이프 사이클 메서드 의 상태를 관리하는 대신 ExecutorService 관리 (생성 / 종료)를 사용자 지정 서비스로 이동 합니다.

ExecutorService서비스 =>에서 생성 onCreate()하고 올바르게 종료하십시오.onDestroy()

권장 종료 방법 ExecutorService:

Java ExecutorService를 올바르게 종료하는 방법


3

ExecutorService는 시스템 리소스를 확보하고 정상적인 애플리케이션 종료를 허용하는 데 더 이상 필요하지 않으면 종료해야합니다. ExecutorService의 스레드는 비 데몬 스레드 일 수 있으므로 정상적인 응용 프로그램 종료를 방지 할 수 있습니다. 즉, 응용 프로그램은 기본 방법을 완료 한 후에도 계속 실행됩니다.

참고 도서

Chaper : 14 페이지 : 814


0

ExecutorService에서 shutdown ()을 호출하는 이유

오늘 저는 기계에서 일련의 작업을 시작하기 전에 기계가 준비 될 때까지 기다려야하는 상황에 직면했습니다.

이 컴퓨터에 REST 호출을합니다. 503 (서버를 사용할 수 없음)을받지 못하면 컴퓨터가 내 요청을 처리 할 준비가 된 것입니다. 따라서 첫 번째 REST 호출에 대해 200 (성공)을 얻을 때까지 기다립니다.

이를 달성하는 방법에는 여러 가지가 있습니다. ExecutorService를 사용하여 스레드를 만들고 매 X 초마다 실행되도록 예약했습니다. 그래서, 조건에 따라이 스레드를 중지해야합니다.이 항목을 확인하십시오.

final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
    Runnable task = () -> {
        try {
            int statusCode = restHelper.firstRESTCall();

            if (statusCode == 200) {
                executor.shutdown();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    };

    int retryAfter = 60;
    executor.scheduleAtFixedRate(task, 0, retryAfter, TimeUnit.SECONDS);

두 번째 질문, 안드로이드 플랫폼에 대한 조금 더 작은 문제입니다.

좀 더 컨텍스트를 제공하면 대답 할 수있을 것입니다! 또한 Android 개발 경험으로 볼 때 스레드가 거의 필요하지 않습니다. 성능을 위해 스레드가 필요한 게임이나 앱을 개발하고 있습니까? 그렇지 않은 경우 Android에서는 위에서 설명한 시나리오와 같은 문제를 해결할 수있는 다른 방법이 있습니다. 오히려 TimerTask, AsyncTask 또는 Handlers 또는 Loaders를 컨텍스트에 따라 사용할 수 있습니다. UIThread가 오래 기다리면 무슨 일이 일어나는지 알기 때문입니다.


0

이것은 ScheduledExecutorService와 같은 계획된 작업에도 불구하고 진짜입니다. 예약 된 할당의 새로운 케이스는 실행되지 않습니다.

N 심부름을 실행하는 에이전트 관리가있는 편리한 응용 프로그램이있을 것으로 예상해야합니다.

그 의미를 쉽게 알아 차리지 못하나요? 에이전트 관리에 더 많은 할당을 제출할 수있는 옵션이없는 애플리케이션이 필요할 수 있으며 그 동안 현재 N 개의 작업이 완료 될 때까지 꽉 조여야합니다.

결국 심부름이 끝날 것이라고 완전히 긍정적 인 경우를 제외하고는 주어진 휴식 시간 동안 꽉 앉아 있어야하고 그 후에는 실행중인 줄을 버리고 나가기 만하면됩니다.

귀하의 활동이 간섭에 반응하도록 의도 된 경우 이는 잘 작동합니다.

또 다른 흥미로운 상황은 활동을 수행하는 ScheduledExecutorService가있는 지점입니다.

활동 체인을 중지하는 가장 좋은 방법은 shutdown ()을 호출하는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.