해결된 질문
작성
·
105
·
수정됨
0
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? 예
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예
3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예
[질문 내용]
ExecutorService 우아한 종료 - 구현
01:07 close() 메소드 설명 부분에
"shutdown()
을 호출하고, 하루를 기다려도 작업이 완료되지 않으면 shutdownNow()
를 호출한다." 에 오류가 있어 보입니다.
"shutdown()
을 호출하고, 작업이 완료될 때까지 무한정 반복대기한다. 인터럽트가 발생하면 shutdownNow()
를 호출한다." 로 변경해야 하지 않나요?
Eclipse Temurin-21.0.4+7 (JDK 21) 버전 코드 원문
public interface ExecutorService implements Executor, AutoClosable {
// ..
@Override
default void close() {
boolean terminated = isTerminated();
if (!terminated) {
shutdown();
boolean interrupted = false;
// 작업 미완료시 재시도
while (!terminated) {
try {
// 하루간 작업 종료 대기, 작업 미완료시 `false` 반환
terminated = awaitTermination(1L, TimeUnit.DAYS);
} catch (InterruptedException e) {
if (!interrupted) {
shutdownNow();
interrupted = true;
}
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}
}
1일이 지났다고 해서 interrupt() 를 호출하지 않고 재시도 하는 것으로 보입니다.
MyExecutor 로 close() 메소드 대기 시간을 1일 -> 1초로 조정하여 오버라이드합니다.
10초간 대기하는 Task 를 실행시킵니다.
class ShutdownTest {
record CallableSleepTask(
String name,
long sleepMs
) implements Callable<Long> {
@Override
public Long call() throws Exception {
sleep(this.sleepMs);
return this.sleepMs;
}
}
static class MyExecutor extends ThreadPoolExecutor {
public MyExecutor() {
super(1, 1, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
}
@Override
public void close() {
boolean terminated = isTerminated();
if (!terminated) {
shutdown();
boolean interrupted = false;
while (!terminated) {
try {
// 종료 대기 시간 1초로 조정
terminated = awaitTermination(1L, TimeUnit.SECONDS);
} catch (InterruptedException e) {
if (!interrupted) {
shutdownNow();
interrupted = true;
}
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}
}
@DisplayName("Should wait infinitely when .close()")
@Test
void executorServiceCloseTest() {
// given
try (ExecutorService myExecutor = new MyExecutor()) {
log("작업 시작");
CallableSleepTask sleepTask = new CallableSleepTask("test", 10_000L);
myExecutor.submit(sleepTask); // 10 초간 테스크 실행
log("작업 진행중.. close 대기");
// 기다리지 않고 .close() 자동 호출
}
}
}
실행 결과
18:38:39.524 [ main] 작업 시작
18:38:39.527 [ main] 작업 진행중.. close 대기
(약 10초 대기 후 종료)
Process finished with exit code 0
테스크 종료를 위해 10초 대기가 이뤄졌습니다.
close 가 조정된 대기시간인 1초 뒤에 인터럽트를 발생시켰다면 인터럽트 로그가 남았을 것이고, shutdownNow()가 호출됐다면 10초 대기없이 즉시 종료되었을 것입니다.
따라서 정정이 필요해보여요.
close 메소드는 "shutdown()
을 호출하고, 작업 완료시까지 무한정 반복대기한다. 인터럽트가 발생하면 shutdownNow()
를 호출한다."
답변 3
1
안녕하세요. milkcoke님
말씀하신 내용이 맞네요 🙂
코드로 검증까지 해주셔서 감사합니다.
1일마다 반복해서 스레드가 깨어나는 이유는 1일이라는 충분한 대기 시간을 통해 프로세스 성능에 영향을 최소화 하면서, 또 해당 스레드가 완전히 멈춘 것 처럼 보이지는 않도록 하기 위한 최소한의 장치로 보이네요.
다음 버전에 패치할게요!
0
0
안녕하세요, 인프런 AI 인턴입니다. milkcoke님.
ExecutorService의 close()
메소드에 대해 지적하신 부분과 함께 제시하신 증명 코드, 실행 결과 등을 보았습니다. 설명해주신 것처럼, close()
메소드는 shutdown()
을 호출한 후, 작업이 모두 완료될 때까지 awaitTermination
을 사용하여 무한정 대기하는 방식으로 설계되어 있습니다. 인터럽트가 발생하면 대기가 중단되고 shutdownNow()
가 호출되게 되어 있죠.
이와 관련하여 유사한 질문과 답변을 아래 링크에서 참고할 수 있습니다. 이 링크에서는 ExecutorService
의 명확한 종료 방법과 관련된 코드 동작에 대해 다루고 있습니다.
이 링크에서는 ExecutorService
의 종료 방법에 대한 잘못된 이해로 인한 문제를 해결하면서, 정확한 종료 절차에 대한 설명을 제공하고 있습니다. 본 강의의 해당 부분이 잘못 설명되었다면, 강의를 제공하신 지식공유자께 제보하여 수정될 수 있도록 유도하는 것이 좋겠습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
영한님 확인 감사합니다!!
(_ _)