Unit 7.7 — 스레드 풀 종료

Psj·2026년 5월 26일

F-lab

목록 보기
151/230

Unit 7.7 — 스레드 풀 종료

F-LAB JAVA · 4주차 · Phase 7 · Executor 프레임워크
🏆 Phase 7 완주 — ★ 4주차 2차 정점 완료


📌 학습 목표

이 Unit을 끝내면 다음을 답할 수 있어야 한다.

  • shutdown() 의 동작 은?
  • shutdownNow() 의 동작 은?
  • shutdown vs shutdownNow 의 차이는?
  • awaitTermination() 의 역할 은?
  • graceful shutdown 패턴 은?
  • 종료 후 작업 제출 시 어떻게 되나?
  • 종료 상태 조회 (isShutdown / isTerminated) 는?
  • 종료하지 않으면 어떤 문제가?
  • Phase 7 전체 의 종합은?

🎯 핵심 한 문장

스레드 풀은 사용 후 반드시 종료해야 하며, shutdown() 은 진행·대기 작업을 모두 완료한 뒤 종료하고, shutdownNow() 는 진행 작업을 인터럽트하고 대기 작업을 반환하며 즉시 종료를 시도한다.
shutdown() 은 새 작업 수락을 거부하되 이미 제출된 작업 (실행 중 + 큐 대기) 은 모두 완료하는 우아한 종료다.
shutdownNow() 는 실행 중인 작업에 인터럽트를 보내고 큐에 대기 중이던 미실행 작업 목록 (List<Runnable>) 을 반환하며 즉시 종료를 시도한다 (인터럽트를 처리하지 않는 작업은 계속 실행될 수 있음).
awaitTermination(timeout) 은 종료가 완료될 때까지 (또는 타임아웃까지) 블로킹하여 대기한다.
권장 패턴은 shutdown() → awaitTermination() → (타임아웃 시) shutdownNow() 순서의 graceful shutdown 으로, 종료하지 않으면 스레드가 살아남아 JVM 이 종료되지 않거나 자원이 누수된다.

비유 — 가게 마감

스레드 풀 종료 = 가게 마감:

shutdown() = 정상 마감:
  - "더 이상 주문 안 받습니다"
  - 단, 받은 주문은 다 완료
  - 손님 다 나가면 마감

shutdownNow() = 비상 마감:
  - "지금 당장 닫습니다"
  - 진행 중 요리 중단 (인터럽트)
  - 대기 주문 목록 반환 (미처리)

awaitTermination() = 마감 확인:
  - "다 끝났나?" 기다림
  - 시간 제한 (10분만 대기)

graceful shutdown = 우아한 마감:
  1. 주문 그만 받기 (shutdown)
  2. 완료 기다리기 (awaitTermination)
  3. 너무 오래 걸리면 강제 (shutdownNow)

종료 안 하면:
  - 직원이 안 퇴근 (스레드 살아있음)
  - 가게 못 닫음 (JVM 종료 X)

→ shutdown (정상), shutdownNow (비상), awaitTermination (대기), graceful 패턴.


🧭 9개 섹션 로드맵

1. shutdown()의 동작
2. shutdownNow()의 동작
3. shutdown vs shutdownNow
4. awaitTermination()
5. graceful shutdown 패턴
6. 종료 후 작업 제출
7. 종료 상태 조회
8. Phase 7 완주 정리
9. 면접 + 자기 점검 + Phase 7 졸업 시험

1️⃣ shutdown()의 동작

1.1 shutdown()

shutdown():

  우아한 종료.
  - 새 작업 수락 거부
  - 이미 제출된 작업 완료
    (실행 중 + 큐 대기)
  - 완료 후 종료

1.2 동작 흐름

shutdown 흐름:

  shutdown() 호출
    ↓
  새 작업 거부 (RejectedExecutionException)
    ↓
  실행 중 작업 완료
    ↓
  큐 대기 작업 모두 처리
    ↓
  스레드 종료
    ↓
  Terminated

1.3 코드

ExecutorService executor = Executors.newFixedThreadPool(4);

// 작업 제출
executor.submit(task1);
executor.submit(task2);

// 종료 시작
executor.shutdown();
// task1, task2 완료까지 실행
// 새 작업은 거부

// executor.submit(task3);   // RejectedExecutionException

1.4 블로킹 안 함

shutdown 은 블로킹 X:

  shutdown() 호출:
    - 즉시 반환 (블로킹 X)
    - 종료 "시작"만
    - 실제 종료는 백그라운드

  종료 대기하려면:
    - awaitTermination()

1.5 ILIC 의 맥락

@Service
public class ShutdownExample {
    
    private final ExecutorService executor = Executors.newFixedThreadPool(4);
    
    public void submitWork(Shipment shipment) {
        executor.submit(() -> process(shipment));
    }
    
    @PreDestroy
    public void shutdown() {
        executor.shutdown();   // 우아한 종료 시작
        // 제출된 작업 모두 완료 후 종료
        // 새 작업 거부
        log.info("스레드 풀 종료 시작");
    }
    
    private void process(Shipment s) { }
}

1.6 자기 점검 답변

shutdown()의 동작은?

:
1. 정의:

  • 우아한 종료
  • 새 작업 거부
  1. 흐름:

    • 제출된 작업 완료
    • 큐 대기도 처리
  2. 블로킹 X:

    • 즉시 반환
    • 종료 시작만
  3. 대기:

    • awaitTermination

2️⃣ shutdownNow()의 동작

2.1 shutdownNow()

shutdownNow():

  즉시 종료 시도.
  - 실행 중 작업 인터럽트
  - 큐 대기 작업 반환 (List<Runnable>)
  - 즉시 종료 시도

2.2 동작

shutdownNow 흐름:

  shutdownNow() 호출
    ↓
  새 작업 거부
    ↓
  실행 중 작업 인터럽트 (interrupt())
    ↓
  큐 대기 작업 반환 (미실행)
    ↓
  즉시 종료 시도

2.3 미실행 작업 반환

ExecutorService executor = Executors.newFixedThreadPool(2);

// 많은 작업 제출
for (int i = 0; i < 100; i++) {
    executor.submit(task);
}

// 즉시 종료
List<Runnable> notExecuted = executor.shutdownNow();
// notExecuted: 큐에 대기 중이던 미실행 작업들
log.info("미실행 작업: {}개", notExecuted.size());

2.4 인터럽트 처리 의존

인터럽트 처리 의존:

  shutdownNow 는 인터럽트만 보냄:
    - 작업이 인터럽트 처리해야 멈춤
    - 처리 안 하면 계속 실행

  → 협력적 (강제 X)
  → 작업이 인터럽트 확인 필요

2.5 인터럽트 무시 작업

// ❌ 인터럽트 무시 작업
executor.submit(() -> {
    while (true) {   // 인터럽트 확인 X
        doWork();
    }
    // shutdownNow 해도 안 멈춤
});

// ✓ 인터럽트 처리
executor.submit(() -> {
    while (!Thread.currentThread().isInterrupted()) {
        doWork();
    }
    // shutdownNow 시 멈춤
});

2.6 ILIC 의 맥락

@Service
public class ShutdownNowExample {
    
    private final ExecutorService executor = Executors.newFixedThreadPool(4);
    
    public void emergencyShutdown() {
        // 즉시 종료
        List<Runnable> pending = executor.shutdownNow();
        
        log.warn("긴급 종료: 미실행 {}개", pending.size());
        
        // 미실행 작업 저장 (나중에 재처리)
        for (Runnable task : pending) {
            if (task instanceof ShipmentTask st) {
                deferredRepository.save(st.getShipment());
            }
        }
    }
    
    // 작업은 인터럽트 처리 필요
    public void submitInterruptible(Shipment shipment) {
        executor.submit(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                process(shipment);
                break;
            }
            // shutdownNow 시 인터럽트로 멈춤
        });
    }
    
    private void process(Shipment s) { }
    record ShipmentTask(Shipment shipment) implements Runnable {
        public void run() {}
        Shipment getShipment() { return shipment; }
    }
}

2.7 자기 점검 답변

shutdownNow()의 동작은?

:
1. 정의:

  • 즉시 종료 시도
  • 인터럽트
  1. 반환:

    • 미실행 작업 (List)
  2. 인터럽트 의존:

    • 작업이 처리해야
    • 무시하면 계속
  3. 협력적:

    • 강제 X

3️⃣ shutdown vs shutdownNow

3.1 비교

항목shutdown()shutdownNow()
새 작업거부거부
실행 중완료인터럽트
큐 대기완료반환 (미실행)
반환값voidList
속도느림 (완료)빠름 (즉시)
손실X미실행 손실

3.2 핵심 차이

핵심 차이:

shutdown:
  - 모두 완료 (우아)
  - 손실 X

shutdownNow:
  - 즉시 (인터럽트)
  - 미실행 손실 (반환)

3.3 선택

선택:

shutdown:
  - 정상 종료
  - 작업 완료 보장
  - 일반적

shutdownNow:
  - 긴급 종료
  - 즉시 멈춤
  - 작업 포기 OK

3.4 시각화

shutdown vs shutdownNow:

shutdown:
  실행 중: [████████] 완료
  큐 대기: [████] 처리
  → 모두 완료 후 종료

shutdownNow:
  실행 중: [████|인터럽트] 중단
  큐 대기: [반환] 미실행
  → 즉시 종료

3.5 함께 사용

// graceful: shutdown 먼저, 안 되면 shutdownNow
executor.shutdown();
try {
    if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
        // 30초 내 안 끝나면
        executor.shutdownNow();   // 강제
    }
} catch (InterruptedException e) {
    executor.shutdownNow();
    Thread.currentThread().interrupt();
}

3.6 ILIC 의 맥락

@Service
public class ShutdownComparison {
    
    private final ExecutorService normalExecutor = Executors.newFixedThreadPool(4);
    private final ExecutorService urgentExecutor = Executors.newFixedThreadPool(4);
    
    // 정상 종료 — shutdown
    public void normalShutdown() {
        normalExecutor.shutdown();
        // 모든 배송 처리 완료 후 종료
    }
    
    // 긴급 종료 — shutdownNow
    public void urgentShutdown() {
        List<Runnable> pending = urgentExecutor.shutdownNow();
        // 즉시 중단, 미처리 반환
        savePendingTasks(pending);
    }
    
    private void savePendingTasks(List<Runnable> tasks) { }
}

3.7 자기 점검 답변

shutdown vs shutdownNow 차이는?

:
1. shutdown:

  • 모두 완료
  • 손실 X
  1. shutdownNow:

    • 인터럽트
    • 미실행 반환 (손실)
  2. 선택:

    • 정상: shutdown
    • 긴급: shutdownNow
  3. 함께:

    • shutdown → 안 되면 shutdownNow

4️⃣ awaitTermination()

4.1 awaitTermination()

boolean awaitTermination(long timeout, TimeUnit unit) 
    throws InterruptedException;

4.2 역할

awaitTermination 역할:

  종료 완료까지 대기 (블로킹).
  - shutdown 후 호출
  - 모든 작업 완료까지
  - 타임아웃 가능

반환:
  - true: 종료 완료
  - false: 타임아웃 (미완료)

4.3 사용

executor.shutdown();   // 종료 시작 (블로킹 X)

// 종료 대기
boolean terminated = executor.awaitTermination(30, TimeUnit.SECONDS);

if (terminated) {
    log.info("정상 종료");
} else {
    log.warn("타임아웃 (미완료)");
    executor.shutdownNow();   // 강제
}

4.4 shutdown 과 함께

shutdown + awaitTermination:

  shutdown():
    - 종료 시작 (블로킹 X)

  awaitTermination():
    - 완료 대기 (블로킹 O)

  → shutdown 후 awaitTermination
  → 완료 보장

4.5 반복 대기

// 긴 종료 대기 (반복)
executor.shutdown();
while (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
    log.info("아직 종료 중...");
    // 계속 대기 또는 shutdownNow
}
log.info("종료 완료");

4.6 ILIC 의 맥락

@Service
public class AwaitTerminationExample {
    
    private final ExecutorService executor = Executors.newFixedThreadPool(4);
    
    @PreDestroy
    public void shutdown() {
        executor.shutdown();   // 종료 시작
        
        try {
            // 최대 30초 대기
            if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
                log.warn("30초 내 미종료, 강제 종료");
                executor.shutdownNow();   // 강제
                
                // 추가 대기
                if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
                    log.error("종료 실패");
                }
            }
            log.info("스레드 풀 정상 종료");
        } catch (InterruptedException e) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}

4.7 자기 점검 답변

awaitTermination()의 역할은?

:
1. 역할:

  • 종료 완료 대기
  • 블로킹
  1. 반환:

    • true: 완료
    • false: 타임아웃
  2. 사용:

    • shutdown 후
    • 완료 보장
  3. 타임아웃 시:

    • shutdownNow

5️⃣ graceful shutdown 패턴

5.1 표준 패턴

// graceful shutdown 표준 패턴
public void gracefulShutdown(ExecutorService executor) {
    executor.shutdown();   // 1. 새 작업 거부
    try {
        // 2. 완료 대기
        if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
            // 3. 타임아웃 시 강제
            executor.shutdownNow();
            // 4. 강제 후 대기
            if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
                log.error("종료 실패");
            }
        }
    } catch (InterruptedException e) {
        // 5. 인터럽트 시 강제
        executor.shutdownNow();
        Thread.currentThread().interrupt();
    }
}

5.2 단계 설명

graceful shutdown 단계:

1. shutdown()
   - 새 작업 거부

2. awaitTermination(timeout)
   - 완료 대기

3. (타임아웃) shutdownNow()
   - 강제 종료

4. awaitTermination(추가)
   - 강제 후 대기

5. (인터럽트) shutdownNow()
   - 예외 처리

5.3 왜 이 순서

순서 이유:

  먼저 우아하게 (shutdown):
    - 작업 완료 기회

  안 되면 강제 (shutdownNow):
    - 무한 대기 방지

  → 우아 시도 후 강제
  → 균형

5.4 Spring 의 종료

// Spring — @PreDestroy
@Service
public class GracefulService {
    private final ExecutorService executor = Executors.newFixedThreadPool(4);
    
    @PreDestroy
    public void destroy() {
        shutdownGracefully(executor, 30);
    }
    
    private void shutdownGracefully(ExecutorService executor, int seconds) {
        executor.shutdown();
        try {
            if (!executor.awaitTermination(seconds, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}

// 또는 Spring ThreadPoolTaskExecutor
// setWaitForTasksToCompleteOnShutdown(true)
// setAwaitTerminationSeconds(30)

5.5 종료 훅

// JVM 종료 훅
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
    log.info("JVM 종료, 스레드 풀 정리");
    executor.shutdown();
    try {
        executor.awaitTermination(10, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        executor.shutdownNow();
    }
}));

5.6 ILIC 의 맥락

@Service
public class ShipmentGracefulShutdown {
    
    private final ExecutorService executor = Executors.newFixedThreadPool(8);
    
    @PreDestroy
    public void shutdown() {
        log.info("배송 처리 풀 종료 시작");
        executor.shutdown();   // 1. 새 작업 거부
        
        try {
            // 2. 진행 배송 완료 대기 (60초)
            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                log.warn("60초 초과, 강제 종료");
                // 3. 강제 종료 + 미처리 회수
                List<Runnable> pending = executor.shutdownNow();
                log.warn("미처리 배송: {}개", pending.size());
                savePendingShipments(pending);
                
                // 4. 강제 후 대기
                if (!executor.awaitTermination(15, TimeUnit.SECONDS)) {
                    log.error("배송 풀 종료 실패");
                }
            }
            log.info("배송 처리 풀 정상 종료");
        } catch (InterruptedException e) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
    
    private void savePendingShipments(List<Runnable> tasks) { }
}

5.7 자기 점검 답변

graceful shutdown 패턴은?

:
1. 패턴:

  • shutdown → awaitTermination
  • → (타임아웃) shutdownNow
  1. 단계:

    • 우아 시도
    • 안 되면 강제
  2. 이유:

    • 완료 기회 + 무한 대기 방지
  3. Spring:

    • @PreDestroy
    • ThreadPoolTaskExecutor

6️⃣ 종료 후 작업 제출

6.1 거부

종료 후 제출:

  shutdown/shutdownNow 후:
    - 새 작업 제출 시
    - RejectedExecutionException

  → 종료 시작하면 거부

6.2 예외

executor.shutdown();

// 종료 후 제출
try {
    executor.submit(task);   // RejectedExecutionException
} catch (RejectedExecutionException e) {
    log.warn("종료된 풀에 제출");
}

6.3 거부 정책 적용

종료 후 거부:

  RejectedExecutionHandler 적용:
    - AbortPolicy: 예외 (기본)
    - 커스텀: 다르게 처리

  → 종료 = 거부 상황

6.4 상태 확인 후 제출

// 제출 전 상태 확인
if (!executor.isShutdown()) {
    executor.submit(task);
} else {
    log.warn("풀 종료됨, 제출 불가");
    // 대체 처리
}

6.5 ILIC 의 맥락

@Service
public class SubmitAfterShutdown {
    
    private final ExecutorService executor = Executors.newFixedThreadPool(4);
    private volatile boolean shuttingDown = false;
    
    public boolean submitShipment(Shipment shipment) {
        if (shuttingDown || executor.isShutdown()) {
            log.warn("종료 중, 제출 거부: {}", shipment.getId());
            deferredQueue.offer(shipment);   // 대체 처리
            return false;
        }
        
        try {
            executor.submit(() -> process(shipment));
            return true;
        } catch (RejectedExecutionException e) {
            log.warn("제출 거부 (종료): {}", shipment.getId());
            deferredQueue.offer(shipment);
            return false;
        }
    }
    
    @PreDestroy
    public void shutdown() {
        shuttingDown = true;
        executor.shutdown();
    }
    
    private final Queue<Shipment> deferredQueue = new ConcurrentLinkedQueue<>();
    private void process(Shipment s) { }
}

6.6 자기 점검 답변

종료 후 작업 제출 시 어떻게 되나?

:
1. 거부:

  • RejectedExecutionException
  1. 거부 정책:

    • 적용됨
  2. 확인:

    • isShutdown() 후 제출
  3. 대체:

    • 대기 큐 등

7️⃣ 종료 상태 조회

7.1 상태 메서드

boolean isShutdown();    // 종료 시작 여부
boolean isTerminated();  // 종료 완료 여부

7.2 isShutdown

isShutdown:

  shutdown/shutdownNow 호출 후 true.
  - 종료 "시작" 여부
  - 작업 완료 여부 무관

7.3 isTerminated

isTerminated:

  모든 작업 완료 + 종료 후 true.
  - 완전 종료 여부
  - shutdown 후 작업 끝나면

7.4 상태 흐름

상태 흐름:

  Running:
    - isShutdown: false
    - isTerminated: false

  shutdown() 후 (작업 진행):
    - isShutdown: true
    - isTerminated: false

  작업 완료 후:
    - isShutdown: true
    - isTerminated: true

7.5 활용

executor.shutdown();

// 종료 시작 확인
if (executor.isShutdown()) {
    log.info("종료 시작됨");
}

// 완전 종료 확인 (폴링 대신 awaitTermination 권장)
while (!executor.isTerminated()) {
    Thread.sleep(100);
}
log.info("완전 종료");

// 더 나은 방법
executor.awaitTermination(30, TimeUnit.SECONDS);

7.6 ILIC 의 맥락

@Service
public class TerminationStatus {
    
    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
        4, 8, 60L, TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(100)
    );
    
    // 상태 모니터링
    public void logStatus() {
        log.info("Shutdown: {}, Terminated: {}, Active: {}, Queue: {}",
            executor.isShutdown(),
            executor.isTerminated(),
            executor.getActiveCount(),
            executor.getQueue().size());
    }
    
    // 헬스 체크
    public boolean isHealthy() {
        return !executor.isShutdown();   // 종료 안 됨 = 정상
    }
    
    @PreDestroy
    public void shutdown() throws InterruptedException {
        executor.shutdown();
        if (executor.awaitTermination(30, TimeUnit.SECONDS)) {
            log.info("정상 종료 (isTerminated: {})", executor.isTerminated());
        }
    }
}

7.7 자기 점검 답변

종료 상태 조회는?

:
1. isShutdown:

  • 종료 시작 여부
  1. isTerminated:

    • 종료 완료 여부
  2. 흐름:

    • Running → shutdown(true) → terminated(true)
  3. 활용:

    • 모니터링, 헬스 체크

8️⃣ Phase 7 완주 정리

8.1 Phase 7 학습 종합

Phase 7 — Executor 프레임워크 (★ 2차 정점)

Unit 7.1 — 스레드 풀의 필요성
Unit 7.2 — Executor와 ExecutorService
Unit 7.3 — Future와 Callable
Unit 7.4 — ThreadPoolExecutor 내부 (★ 마스터)
Unit 7.5 — 스레드 풀 종류
Unit 7.6 — 작업 큐와 거부 정책
Unit 7.7 — 스레드 풀 종료

8.2 Phase 7 의 큰 그림

Executor 프레임워크:

1. 필요성
   - 직접 생성 문제

2. 추상화
   - Executor/ExecutorService

3. 결과
   - Future/Callable

4. 내부
   - ThreadPoolExecutor

5. 종류
   - Fixed/Cached/Single 등

6. 큐/정책
   - 작업 관리

7. 종료
   - graceful shutdown

8.3 다음 Phase 예고

Phase 7 → Phase 8:
  - 스레드 풀 → 고급 비동기

Phase 8 — 고급 비동기 (3 Unit):
  - CompletableFuture (★ 마스터)
  - ForkJoinPool
  - RecursiveTask

8.4 Phase 7 핵심 통찰

Phase 7 핵심 통찰 5가지:

1. 스레드 풀
   - 재사용, 자원 보호

2. Executor 추상화
   - 제출과 실행 분리

3. ThreadPoolExecutor
   - core → 큐 → max → 거부

4. 풀 종류
   - 용도별 선택

5. graceful shutdown
   - shutdown → await → shutdownNow

8.5 4주차 누적 진행

✅ Phase 1 — 동시성의 기초 (4 Unit)
✅ Phase 2 — 4분면 매트릭스 (3 Unit)
✅ Phase 3 — 스레드 다루기 (5 Unit)
✅ Phase 4 — synchronized & volatile (5 Unit) ★ 1차 정점
✅ Phase 5 — Lock 도구 (4 Unit)
✅ Phase 6 — 스레드 협력 (4 Unit)
✅ Phase 7 — Executor (7 Unit) ★ 2차 정점 ← 완주
⏭ Phase 8 — 고급 비동기 (3 Unit)

총: 32/35 Unit (Phase 7 완주, 약 91%)

8.6 자기 점검 답변

Phase 7의 종합은?

:
1. 7개 Unit:

  • 필요성, 추상화
  • Future, 내부
  • 종류, 큐/정책, 종료
  1. 큰 그림:

    • 스레드 풀 전반
  2. 핵심:

    • 재사용
    • core → 큐 → max
    • graceful shutdown

9️⃣ 면접 + 자기 점검 + Phase 7 졸업 시험

9.1 면접 단골 질문 매핑

Q핵심 답변
shutdown()?우아한 종료 (완료)
shutdownNow()?즉시 (인터럽트, 반환)
차이?완료 vs 인터럽트
awaitTermination()?종료 대기
graceful 패턴?shutdown→await→shutdownNow
종료 후 제출?거부
isShutdown?종료 시작
isTerminated?종료 완료
종료 안 하면?스레드 누수, JVM 종료 X
Phase 7 핵심?Executor 프레임워크

9.2 Phase 7 졸업 시험 50문항

스레드 풀 기초 (12문항)

Q1. 직접 생성 문제? → 비용, 무제한, 관리
Q2. 생성 비용? → OS 스레드, 1MB 스택
Q3. 무제한 위험? → OOM
Q4. 스레드 풀? → 재사용
Q5. 재사용 효과? → 비용 절감
Q6. 구성 요소? → 워커, 큐, 팩토리, 정책
Q7. 처리량 제어? → 동시 수 제한
Q8. 백프레셔? → 과부하 방지
Q9. 적정 크기 CPU? → 코어 + 1
Q10. 적정 크기 I/O? → 더 많이
Q11. 생산자-소비자? → 작업 큐 + 워커
Q12. 장점? → 비용/자원/관리

Executor/Future (13문항)

Q13. Executor? → execute
Q14. ExecutorService? → submit, shutdown
Q15. execute vs submit? → void vs Future
Q16. 예외 처리? → 핸들러 vs get
Q17. Executors? → 팩토리 (위험)
Q18. invokeAll? → 모두 대기
Q19. invokeAny? → 하나만
Q20. Callable? → 반환값 + 예외
Q21. Runnable vs Callable? → void vs V
Q22. Future? → 결과 핸들
Q23. get()? → 블로킹
Q24. cancel()? → 취소
Q25. Future 한계? → 블로킹, 조합

ThreadPoolExecutor (13문항)

Q26. 파라미터? → core/max/keepAlive/queue/handler
Q27. core vs max? → 평상시 vs 최대
Q28. keepAlive? → 유휴 정리
Q29. 작업 흐름? → core→큐→max→거부
Q30. 큐 vs max? → 큐 먼저
Q31. 무제한 큐? → max 무의미
Q32. 거부 정책? → max + 큐 가득
Q33. AbortPolicy? → 예외
Q34. CallerRunsPolicy? → 호출자 (백프레셔)
Q35. DiscardPolicy? → 버림
Q36. LinkedBlockingQueue? → 무제한/제한
Q37. ArrayBlockingQueue? → 고정
Q38. SynchronousQueue? → 직접 전달

풀 종류/종료 (12문항)

Q39. Fixed? → 고정, 무제한 큐
Q40. Cached? → 동적, 무제한 스레드
Q41. Single? → 순차
Q42. Scheduled? → 예약
Q43. WorkStealing? → 일 훔치기
Q44. Virtual? → Java 21+ I/O
Q45. shutdown? → 우아한 종료
Q46. shutdownNow? → 즉시, 반환
Q47. awaitTermination? → 종료 대기
Q48. graceful? → shutdown→await→shutdownNow
Q49. 종료 후 제출? → 거부
Q50. isTerminated? → 완전 종료

9.3 채점

50 / 50 → Phase 7 마스터
45-49   → 거의 마스터
40-44   → 복습
< 40    → Unit 7.1 ~ 7.7 재학습

9.4 추가 심화 질문

Q1: shutdown 후 awaitTermination 안 하면?

답:

  • shutdown 은 블로킹 X
  • 즉시 다음 코드
  • 작업 완료 안 기다림
  • await 로 완료 보장

Q2: Spring 의 우아한 종료?

답:

  • ThreadPoolTaskExecutor
  • setWaitForTasksToCompleteOnShutdown(true)
  • setAwaitTerminationSeconds(N)
  • @PreDestroy 자동

Q3: 종료 안 하면?

답:

  • 스레드 살아있음 (non-daemon)
  • JVM 종료 안 됨
  • 자원 누수
  • @PreDestroy 필수

Q4: shutdownNow 의 인터럽트 한계?

답:

  • 인터럽트만 보냄
  • 작업이 처리해야 멈춤
  • CPU 무한 루프 (인터럽트 확인 X) 안 멈춤
  • 협력 필요

Q5: 데몬 스레드 풀과 종료?

답:

  • 데몬 풀: JVM 종료 시 자동
  • 단, 작업 완료 보장 X
  • 중요 작업은 non-daemon + shutdown
  • 모니터링은 데몬

🎯 핵심 요약 — 3줄 정리

1. shutdown vs shutdownNow

  • shutdown: 완료 후 종료 (우아)
  • shutdownNow: 인터럽트 + 미실행 반환 (즉시)

2. awaitTermination

  • 종료 완료 대기 (블로킹)
  • true: 완료, false: 타임아웃

3. graceful shutdown

  • shutdown → awaitTermination → (타임아웃) shutdownNow
  • 종료 안 하면 스레드 누수, JVM 종료 X

🏆 Phase 7 완주 — Executor 프레임워크 마스터 (★ 2차 정점)

🚀 Phase 7 — Executor 프레임워크 (★ 2차 정점)
  ✅ Unit 7.1 스레드 풀의 필요성
  ✅ Unit 7.2 Executor와 ExecutorService
  ✅ Unit 7.3 Future와 Callable
  ✅ Unit 7.4 ThreadPoolExecutor 내부 (★ 마스터)
  ✅ Unit 7.5 스레드 풀 종류
  ✅ Unit 7.6 작업 큐와 거부 정책
  ✅ Unit 7.7 스레드 풀 종료 ← 여기, Phase 7 완주

→ 스레드 풀 + Executor + Future
→ ThreadPoolExecutor 내부
→ ★ 4주차 2차 정점 완료

📚 다음으로...

Phase 8 — 고급 비동기 (CompletableFuture)

Phase 8 — 고급 비동기 (3 Unit, 4주차 마지막)

Unit 8.1 — CompletableFuture (★ 마스터)
Unit 8.2 — ForkJoinPool
Unit 8.3 — RecursiveTask

4주차 누적 진행

✅ Phase 1~7 (32 Unit, 1·2차 정점 완료)
⏭ Phase 8 — 고급 비동기 (3 Unit)

총: 32/35 Unit (약 91%)

🏆 Phase 7 완주 — Executor 프레임워크 마스터 (★ 2차 정점 완료)

profile
Software Developer

0개의 댓글