Unit 7.3 — Future와 Callable

Psj·6일 전

F-lab

목록 보기
147/197

Unit 7.3 — Future와 Callable

F-LAB JAVA · 4주차 · Phase 7 · Executor 프레임워크


📌 학습 목표

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

  • Callable 의 정의와 Runnable 과의 차이는?
  • Callable 의 반환값과 예외 처리는?
  • Future 의 정의와 역할은?
  • Future.get() / get(timeout) 의 동작은?
  • Future.cancel() / isDone() / isCancelled() 는?
  • Runnable vs Callable 의 차이는?
  • Future.get() 의 블로킹 특성은?
  • Future 의 한계 는?
  • CompletableFuture 가 필요한 이유는?

🎯 핵심 한 문장

Callable 은 결과 값을 반환하고 검사 예외를 던질 수 있는 작업 인터페이스이고, Future 는 그 비동기 작업의 결과를 나중에 받아오는 핸들 (handle) 이다.
Callable<V>V call() throws Exception 메서드를 가져 Runnable 과 달리 반환값 (V) 과 검사 예외 를 지원한다.
Future<V>submit() 이 반환하는 객체로, get() 으로 결과를 받고 (완료까지 블로킹), get(timeout) 으로 타임아웃을 두며, cancel() 로 취소, isDone()/isCancelled() 로 상태를 조회한다.
Future.get() 은 작업이 끝날 때까지 블로킹 하므로, 여러 비동기 작업을 조합하거나 콜백을 연결하기에는 불편하다 (get 마다 대기).
이러한 한계 (블로킹 get, 조합·콜백 어려움, 예외 전파 번거로움) 때문에 자바 8 의 CompletableFuture (다음 Phase) 가 등장하여 논블로킹 콜백 체이닝을 제공한다.

비유 — 세탁소 보관증

Callable + Future = 세탁소:

Callable = 세탁 주문 (결과 있음):
  - "이 옷 세탁해줘" (작업)
  - 세탁된 옷 (반환값)
  - 얼룩 못 빼면 알려줘 (예외)

  vs Runnable = 청소 (결과 없음):
  - "청소해줘" (반환값 X)

Future = 보관증:
  - 주문 후 보관증 받음
  - 나중에 옷 찾으러 옴

Future.get() = 옷 찾기:
  - 보관증 들고 감
  - 아직 안 됐으면 기다림 (블로킹)
  - 완료되면 받음

get(timeout) = 시간 제한:
  - "10분만 기다림"

cancel() = 주문 취소:
  - 아직 안 됐으면 취소

한계:
  - 찾으러 가서 기다려야 (블로킹)
  - 여러 보관증 → 하나씩 기다림 (조합 불편)
  → CompletableFuture (알림 받기)

→ Callable = 결과 있는 작업, Future = 결과 핸들 (블로킹 get), 조합 한계.


🧭 9개 섹션 로드맵

1. Callable의 정의
2. Callable의 반환값과 예외
3. Future의 정의
4. Future.get()과 get(timeout)
5. cancel / isDone / isCancelled
6. Runnable vs Callable
7. Future.get()의 블로킹
8. Future의 한계와 CompletableFuture
9. 면접 + 자기 점검

1️⃣ Callable의 정의

1.1 Callable

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}
// 반환값 V + 검사 예외

1.2 Runnable 과 비교

// Runnable — 반환값 X, 검사 예외 X
public interface Runnable {
    void run();   // void, throws X
}

// Callable — 반환값 O, 검사 예외 O
public interface Callable<V> {
    V call() throws Exception;   // V, throws
}

1.3 Callable 사용

Callable<Integer> task = () -> {
    int result = compute();
    return result;   // 반환값
};

// ExecutorService 에 제출
Future<Integer> future = executor.submit(task);
Integer result = future.get();

1.4 람다로

// 람다 (함수형 인터페이스)
Callable<String> task = () -> {
    return "result";
};

// 메서드 참조
Callable<Result> task2 = this::compute;

1.5 ILIC 의 맥락

@Service
public class CallableBasics {
    
    private final ExecutorService executor = Executors.newFixedThreadPool(10);
    
    // Callable — 운임 계산 (반환값)
    public Future<BigDecimal> calculateFreight(Shipment shipment) {
        Callable<BigDecimal> task = () -> {
            // 계산 (반환)
            return freightCalculator.calculate(shipment);
        };
        return executor.submit(task);
    }
    
    // Callable — 예외 가능
    public Future<TrackingInfo> fetchTracking(String blNo) {
        Callable<TrackingInfo> task = () -> {
            // 검사 예외 던질 수 있음
            return trackingApi.fetch(blNo);   // throws IOException
        };
        return executor.submit(task);
    }
    
    record TrackingInfo() {}
}

1.6 자기 점검 답변

Callable의 정의와 Runnable과의 차이는?

:
1. Callable:

  • V call() throws Exception
  • 반환값 + 예외
  1. Runnable:

    • void run()
    • 반환값 X, 예외 X
  2. 차이:

    • 반환값
    • 검사 예외
  3. 사용:

    • submit + Future

2️⃣ Callable의 반환값과 예외

2.1 반환값

Callable 반환값:

  call() 이 V 반환:
    - 작업 결과
    - Future.get() 으로 회수

  Runnable 은 void:
    - 결과 없음
    - 공유 변수로 우회 (번거로움)

2.2 검사 예외

// Callable — 검사 예외 던질 수 있음
Callable<Data> task = () -> {
    Data data = readFile();   // throws IOException
    return data;
    // checked exception OK
};

// Runnable — checked 예외 못 던짐
Runnable r = () -> {
    // readFile();   // ❌ IOException 못 던짐
    try {
        readFile();   // try-catch 필요
    } catch (IOException e) {
        throw new RuntimeException(e);   // unchecked 로 변환
    }
};

2.3 예외 전파

Callable 예외 전파:

  call() 에서 예외 발생:
    - Future 에 저장
    - get() 시 ExecutionException 으로

  → 예외도 결과처럼 전달

2.4 예외 처리

Callable<Result> task = () -> {
    if (invalid) {
        throw new IllegalStateException("Invalid");
    }
    return compute();
};

Future<Result> future = executor.submit(task);

try {
    Result result = future.get();
} catch (ExecutionException e) {
    Throwable cause = e.getCause();   // IllegalStateException
    handleError(cause);
}

2.5 Runnable 의 결과 우회

// Runnable 로 결과 받기 (번거로움)
AtomicReference<Result> resultRef = new AtomicReference<>();
Runnable r = () -> {
    Result result = compute();
    resultRef.set(result);   // 공유 변수
};
executor.submit(r).get();   // 완료 대기
Result result = resultRef.get();   // 회수

// Callable 이 훨씬 간단
Callable<Result> c = () -> compute();
Result result2 = executor.submit(c).get();

2.6 ILIC 의 맥락

@Service
public class CallableReturnException {
    
    private final ExecutorService executor = Executors.newFixedThreadPool(10);
    
    // 반환값 + 예외
    public BigDecimal calculateWithExceptionHandling(Shipment shipment) {
        Callable<BigDecimal> task = () -> {
            if (shipment.getWeight() == null) {
                throw new IllegalArgumentException("무게 없음");   // 검사/비검사 모두
            }
            return freightCalculator.calculate(shipment);   // 반환
        };
        
        Future<BigDecimal> future = executor.submit(task);
        try {
            return future.get();   // 결과 또는 예외
        } catch (ExecutionException e) {
            log.error("운임 계산 실패: {}", shipment.getId(), e.getCause());
            return BigDecimal.ZERO;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return BigDecimal.ZERO;
        }
    }
}

2.7 자기 점검 답변

Callable의 반환값과 예외 처리는?

:
1. 반환값:

  • call() 이 V 반환
  • Future.get() 회수
  1. 검사 예외:

    • throws Exception
    • Runnable 은 못 던짐
  2. 전파:

    • Future 에 저장
    • get() 시 ExecutionException
  3. 우회 X:

    • Runnable 은 공유 변수 (번거로움)

3️⃣ Future의 정의

3.1 Future

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit) throws ...;
}

3.2 역할

Future 역할:

  비동기 작업의 결과 핸들.
  - 결과 회수 (get)
  - 상태 조회 (isDone)
  - 취소 (cancel)

  → 미래의 결과를 나타냄

3.3 생성

// submit 이 Future 반환
Future<Result> future = executor.submit(() -> compute());

// 작업은 백그라운드 실행
// future 로 나중에 결과

3.4 상태

Future 상태:

  - 진행 중 (실행 중)
  - 완료 (정상)
  - 완료 (예외)
  - 취소됨

조회:
  - isDone(): 완료 여부
  - isCancelled(): 취소 여부

3.5 ILIC 의 맥락

@Service
public class FutureBasics {
    
    private final ExecutorService executor = Executors.newFixedThreadPool(10);
    
    public void demonstrateFuture(Shipment shipment) {
        // Future 받기
        Future<BigDecimal> future = executor.submit(() -> 
            calculateFreight(shipment));
        
        // 다른 작업 (병렬)
        doOtherWork();
        
        // 상태 확인
        if (future.isDone()) {
            log.info("계산 완료");
        }
        
        // 결과 회수
        try {
            BigDecimal freight = future.get();
            log.info("운임: {}", freight);
        } catch (Exception e) {
            log.error("실패", e);
        }
    }
    
    private BigDecimal calculateFreight(Shipment s) { return s.getWeight(); }
    private void doOtherWork() { }
}

3.6 자기 점검 답변

Future의 정의와 역할은?

:
1. 정의:

  • 비동기 결과 핸들
  • submit 이 반환
  1. 역할:

    • 결과 회수 (get)
    • 상태 조회
    • 취소
  2. 상태:

    • 진행/완료/취소
  3. 의미:

    • 미래의 결과

4️⃣ Future.get()과 get(timeout)

4.1 get()

get():

  결과를 받음 (완료까지 블로킹).
  - 완료 → 결과 반환
  - 미완료 → 대기 (블로킹)
  - 예외 → ExecutionException

4.2 get(timeout)

// get(timeout) — 타임아웃
try {
    Result result = future.get(5, TimeUnit.SECONDS);
    // 5초 내 완료 → 결과
} catch (TimeoutException e) {
    // 5초 초과 → 예외 (작업은 계속)
    future.cancel(true);   // 필요 시 취소
}

4.3 예외들

try {
    Result result = future.get();
} catch (InterruptedException e) {
    // 대기 중 인터럽트
    Thread.currentThread().interrupt();
} catch (ExecutionException e) {
    // 작업 중 예외
    Throwable cause = e.getCause();
} catch (TimeoutException e) {
    // get(timeout) 시간 초과
}

4.4 블로킹

get() 블로킹:

  작업 미완료면:
    - 호출 스레드 대기 (블로킹)
    - 완료까지

  → 비동기인데 get 에서 블로킹
  → Future 의 한계

4.5 시각화

get() 동작:

작업 미완료:
  main: submit → get() [블로킹 대기──][결과]
  worker:       [작업────────────────]
                                      ↑ 완료

get(timeout):
  main: get(5초) [대기 5초][TimeoutException]
  worker:        [작업 계속...]
                  ↑ 미완료 (계속 실행)

4.6 ILIC 의 맥락

@Service
public class FutureGet {
    
    private final ExecutorService executor = Executors.newFixedThreadPool(10);
    
    // get — 결과 대기
    public BigDecimal calculate(Shipment shipment) throws Exception {
        Future<BigDecimal> future = executor.submit(() -> 
            freightCalculator.calculate(shipment));
        return future.get();   // 완료까지 대기
    }
    
    // get(timeout) — 타임아웃
    public BigDecimal calculateWithTimeout(Shipment shipment) {
        Future<BigDecimal> future = executor.submit(() -> 
            freightCalculator.calculate(shipment));
        try {
            return future.get(10, TimeUnit.SECONDS);   // 10초
        } catch (TimeoutException e) {
            future.cancel(true);   // 취소
            log.warn("계산 타임아웃: {}", shipment.getId());
            return BigDecimal.ZERO;
        } catch (Exception e) {
            Thread.currentThread().interrupt();
            return BigDecimal.ZERO;
        }
    }
}

4.7 자기 점검 답변

Future.get() / get(timeout)의 동작은?

:
1. get():

  • 완료까지 블로킹
  • 결과 또는 예외
  1. get(timeout):

    • 타임아웃
    • TimeoutException
  2. 예외:

    • InterruptedException
    • ExecutionException
    • TimeoutException
  3. 블로킹:

    • 미완료 시 대기

5️⃣ cancel / isDone / isCancelled

5.1 cancel()

// cancel(mayInterruptIfRunning)
boolean cancelled = future.cancel(true);

// true: 실행 중이면 인터럽트
// false: 실행 중이면 취소 X (대기 중만)

5.2 cancel 동작

cancel 동작:

  아직 시작 안 함:
    - 취소 (실행 안 됨)
    - true 반환

  실행 중:
    - mayInterruptIfRunning=true: 인터럽트
    - false: 그대로 (취소 X)

  이미 완료:
    - 취소 X (false 반환)

5.3 isDone()

// isDone — 완료 여부
boolean done = future.isDone();

// true:
// - 정상 완료
// - 예외 완료
// - 취소됨
// 모두 "완료"

5.4 isCancelled()

// isCancelled — 취소 여부
boolean cancelled = future.isCancelled();

// true: cancel 로 취소됨
// false: 취소 안 됨

5.5 상태 조합

// 상태 확인
if (future.isCancelled()) {
    // 취소됨
} else if (future.isDone()) {
    // 완료 (정상 또는 예외)
    try {
        Result r = future.get();   // 즉시 (이미 완료)
    } catch (ExecutionException e) {
        // 예외 완료
    }
} else {
    // 진행 중
}

5.6 ILIC 의 맥락

@Service
public class FutureControl {
    
    private final ExecutorService executor = Executors.newFixedThreadPool(10);
    
    public void demonstrateControl(Shipment shipment) {
        Future<BigDecimal> future = executor.submit(() -> 
            longCalculation(shipment));
        
        // 상태 확인
        log.info("Done: {}, Cancelled: {}", 
            future.isDone(), future.isCancelled());
        
        // 조건부 취소
        if (shouldCancel()) {
            boolean cancelled = future.cancel(true);   // 인터럽트
            log.info("취소 결과: {}", cancelled);
        }
        
        // 완료 확인 후 결과
        if (future.isDone() && !future.isCancelled()) {
            try {
                BigDecimal result = future.get();   // 즉시
            } catch (Exception e) {
                log.error("실패", e);
            }
        }
    }
    
    private BigDecimal longCalculation(Shipment s) { return s.getWeight(); }
    private boolean shouldCancel() { return false; }
}

5.7 자기 점검 답변

cancel / isDone / isCancelled는?

:
1. cancel():

  • 취소 시도
  • true: 인터럽트
  1. isDone():

    • 완료 여부
    • 정상/예외/취소 모두
  2. isCancelled():

    • 취소 여부
  3. 조합:

    • 상태 확인

6️⃣ Runnable vs Callable

6.1 비교

항목RunnableCallable
메서드run()call()
반환값voidV
검사 예외XO (throws)
도입Java 1.0Java 5
사용execute/submitsubmit

6.2 언제 Runnable

Runnable 사용:

  - 결과 불필요
  - 단순 작업
  - Thread 생성
  - 알림, 로그

예:
  - 백그라운드 작업
  - fire-and-forget

6.3 언제 Callable

Callable 사용:

  - 결과 필요
  - 검사 예외
  - 계산 작업

예:
  - 운임 계산
  - 데이터 조회
  - 파일 읽기

6.4 변환

// Runnable → Callable (결과 추가)
Runnable r = () -> doWork();
Callable<Object> c = Executors.callable(r);   // null 반환
Callable<String> c2 = Executors.callable(r, "result");   // 지정 결과

// submit 은 둘 다 받음
Future<?> f1 = executor.submit(r);          // Runnable
Future<String> f2 = executor.submit(c2);    // Callable

6.5 ILIC 의 맥락

@Service
public class RunnableVsCallable {
    
    private final ExecutorService executor = Executors.newFixedThreadPool(10);
    
    // Runnable — 알림 (결과 불필요)
    public void notify(Shipment shipment) {
        Runnable task = () -> emailService.send(shipment);
        executor.submit(task);   // 결과 안 받음
    }
    
    // Callable — 계산 (결과 필요)
    public Future<BigDecimal> calculate(Shipment shipment) {
        Callable<BigDecimal> task = () -> 
            freightCalculator.calculate(shipment);
        return executor.submit(task);   // 결과 받음
    }
    
    // Callable — 예외 가능 (조회)
    public Future<TrackingInfo> fetch(String blNo) {
        Callable<TrackingInfo> task = () -> 
            trackingApi.fetch(blNo);   // throws IOException
        return executor.submit(task);
    }
    
    record TrackingInfo() {}
}

6.6 자기 점검 답변

Runnable vs Callable 차이는?

:
1. Runnable:

  • run(), void
  • 검사 예외 X
  1. Callable:

    • call(), V
    • throws Exception
  2. 사용:

    • Runnable: 결과 불필요
    • Callable: 결과/예외
  3. 변환:

    • Executors.callable()

7️⃣ Future.get()의 블로킹

7.1 블로킹 특성

Future.get() 블로킹:

  작업 미완료면:
    - 호출 스레드 대기 (블로킹)
    - 완료까지

  → 비동기 작업인데
  → get 에서 동기 대기

7.2 블로킹의 문제

// ❌ 여러 Future 순차 get (블로킹)
Future<A> fa = executor.submit(() -> taskA());
Future<B> fb = executor.submit(() -> taskB());

A a = fa.get();   // taskA 완료까지 블로킹
B b = fb.get();   // taskB 완료까지 블로킹
// 순차 대기 (병렬 제출이지만 get 은 순차)

7.3 그나마 병렬

// 제출은 병렬 (실행은 동시)
Future<A> fa = executor.submit(() -> taskA());   // 시작
Future<B> fb = executor.submit(() -> taskB());   // 시작 (동시)

// get 은 순차지만 작업은 병렬 실행됨
A a = fa.get();   // taskA, taskB 둘 다 실행 중
B b = fb.get();   // taskB 이미 완료됐을 수도

// 전체 시간 ≈ max(taskA, taskB)

7.4 조합의 어려움

// ❌ Future 조합 어려움
Future<A> fa = executor.submit(() -> taskA());
A a = fa.get();   // 블로킹

// a 를 사용하는 작업
Future<B> fb = executor.submit(() -> taskB(a));   // a 필요
B b = fb.get();   // 또 블로킹

// 작업 의존 시 블로킹 연쇄
// → CompletableFuture 가 해결 (콜백)

7.5 콜백 없음

Future 의 콜백 부재:

  Future:
    - "완료되면 알려줘" 불가
    - get 으로 직접 확인 (폴링/블로킹)

  CompletableFuture:
    - thenApply, thenAccept (콜백)
    - 완료 시 자동 실행

7.6 ILIC 의 맥락

@Service
public class FutureBlocking {
    
    private final ExecutorService executor = Executors.newFixedThreadPool(10);
    
    // 블로킹 get (여러 작업)
    public ShipmentSummary process(Shipment shipment) throws Exception {
        // 병렬 제출
        Future<BigDecimal> freightF = executor.submit(() -> 
            calculateFreight(shipment));
        Future<TrackingInfo> trackingF = executor.submit(() -> 
            fetchTracking(shipment.getBlNo()));
        Future<List<Document>> docsF = executor.submit(() -> 
            fetchDocuments(shipment));
        
        // 순차 get (블로킹) — 하지만 작업은 병렬 실행됨
        BigDecimal freight = freightF.get();   // 블로킹
        TrackingInfo tracking = trackingF.get();   // 블로킹
        List<Document> docs = docsF.get();   // 블로킹
        
        // 전체 시간 ≈ 가장 긴 작업
        return new ShipmentSummary(freight, tracking, docs);
    }
    
    // CompletableFuture 면 콜백으로 더 우아 (Phase 8)
    
    private BigDecimal calculateFreight(Shipment s) { return s.getWeight(); }
    private TrackingInfo fetchTracking(String bl) { return new TrackingInfo(); }
    private List<Document> fetchDocuments(Shipment s) { return List.of(); }
    record TrackingInfo() {}
    record Document() {}
    record ShipmentSummary(BigDecimal freight, TrackingInfo tracking, List<Document> docs) {}
}

7.7 자기 점검 답변

Future.get()의 블로킹 특성은?

:
1. 블로킹:

  • 미완료 시 대기
  • 완료까지
  1. 문제:

    • 비동기인데 get 동기
    • 순차 get
  2. 조합 어려움:

    • 의존 작업 블로킹 연쇄
  3. 콜백 없음:

    • "완료 시 알림" 불가

8️⃣ Future의 한계와 CompletableFuture

8.1 Future 의 한계

Future 의 한계:

1. 블로킹 get
   - 결과 받으려면 대기

2. 조합 어려움
   - 여러 Future 연결 불편

3. 콜백 없음
   - 완료 시 자동 실행 X

4. 예외 처리 번거로움
   - try-catch (ExecutionException)

5. 수동 완료 X
   - 외부에서 완료 설정 불가

8.2 CompletableFuture 등장

CompletableFuture (Java 8):

  Future 의 한계 극복:
    - 논블로킹 콜백 (thenApply 등)
    - 조합 (thenCompose, thenCombine)
    - 예외 처리 (exceptionally)
    - 수동 완료 (complete)

8.3 비교

// Future — 블로킹
Future<String> future = executor.submit(() -> fetch());
String result = future.get();   // 블로킹
String processed = process(result);

// CompletableFuture — 콜백 (논블로킹)
CompletableFuture.supplyAsync(() -> fetch(), executor)
    .thenApply(result -> process(result))   // 콜백
    .thenAccept(processed -> save(processed));   // 콜백
// 블로킹 없음 (완료 시 자동)

8.4 조합 비교

// Future — 조합 어려움
Future<A> fa = executor.submit(() -> taskA());
A a = fa.get();   // 블로킹
Future<B> fb = executor.submit(() -> taskB(a));
B b = fb.get();   // 블로킹

// CompletableFuture — 조합 쉬움
CompletableFuture.supplyAsync(() -> taskA(), executor)
    .thenCompose(a -> CompletableFuture.supplyAsync(() -> taskB(a), executor))
    .thenAccept(b -> use(b));
// 콜백 체이닝 (블로킹 X)

8.5 언제 어느 것

선택:

Future:
  - 단순 비동기 결과
  - 블로킹 OK
  - 레거시

CompletableFuture:
  - 논블로킹
  - 조합/콜백
  - 현대 비동기
  - 권장 (Phase 8)

8.6 ILIC 의 맥락

@Service
public class FutureLimitations {
    
    private final ExecutorService executor = Executors.newFixedThreadPool(10);
    
    // ❌ Future — 블로킹, 조합 어려움
    public ShipmentResult processWithFuture(Shipment shipment) throws Exception {
        Future<BigDecimal> freightF = executor.submit(() -> calculateFreight(shipment));
        BigDecimal freight = freightF.get();   // 블로킹
        
        Future<Invoice> invoiceF = executor.submit(() -> createInvoice(shipment, freight));
        Invoice invoice = invoiceF.get();   // 또 블로킹
        
        return new ShipmentResult(freight, invoice);
    }
    
    // ✓ CompletableFuture — 논블로킹 (Phase 8)
    public CompletableFuture<ShipmentResult> processWithCF(Shipment shipment) {
        return CompletableFuture
            .supplyAsync(() -> calculateFreight(shipment), executor)
            .thenApply(freight -> {
                Invoice invoice = createInvoice(shipment, freight);
                return new ShipmentResult(freight, invoice);
            });
        // 블로킹 X, 콜백 체이닝
    }
    
    private BigDecimal calculateFreight(Shipment s) { return s.getWeight(); }
    private Invoice createInvoice(Shipment s, BigDecimal f) { return new Invoice(); }
    record Invoice() {}
    record ShipmentResult(BigDecimal freight, Invoice invoice) {}
}

8.7 자기 점검 답변

Future의 한계와 CompletableFuture가 필요한 이유는?

:
1. Future 한계:

  • 블로킹 get
  • 조합 어려움
  • 콜백 없음
  1. CompletableFuture:

    • 논블로킹 콜백
    • 조합 (thenCompose)
    • 예외 처리
  2. 비교:

    • Future: 블로킹
    • CF: 콜백 체이닝
  3. 선택:

    • 현대: CompletableFuture

9️⃣ 면접 + 자기 점검

9.1 면접 단골 질문 매핑

Q핵심 답변
Callable?call(), 반환값 + 예외
Runnable vs Callable?void vs V, 예외
Future?비동기 결과 핸들
get()?완료까지 블로킹
get(timeout)?타임아웃
cancel()?취소 (인터럽트)
isDone()?완료 여부
get 블로킹?미완료 시 대기
Future 한계?블로킹, 조합 어려움
CompletableFuture?논블로킹 콜백

9.2 자기 점검 체크리스트

Callable

  • 정의
  • 반환값/예외

Future

  • 정의
  • 역할

get

  • 블로킹
  • timeout

제어

  • cancel
  • isDone/isCancelled

Runnable vs Callable

  • 차이

블로킹

  • get 특성
  • 조합 어려움

한계

  • CompletableFuture

9.3 추가 심화 질문

Q1: FutureTask?

답:

  • Future + Runnable 구현
  • Callable 래핑
  • 직접 실행 가능
  • Future 의 기본 구현체

Q2: get() 두 번 호출?

답:

  • 첫 get: 완료 대기 + 결과
  • 둘째 get: 즉시 같은 결과
  • 결과 캐싱
  • 예외도 동일

Q3: cancel(false) vs cancel(true)?

답:

  • false: 실행 중이면 취소 X (대기 중만)
  • true: 실행 중이면 인터럽트
  • 작업이 인터럽트 처리해야
  • 처리 안 하면 계속 실행

Q4: Future 결과 캐싱?

답:

  • get 결과 저장
  • 반복 get 동일 결과
  • 한 번 계산
  • 멱등성

Q5: ExecutorCompletionService?

답:

  • 완료 순서대로 take
  • 여러 Future 효율적 회수
  • 빠른 것부터
  • invokeAll 대안

🎯 핵심 요약 — 3줄 정리

1. Callable

  • call(), 반환값 + 검사 예외
  • Runnable (void, 예외 X) 과 차이

2. Future

  • 비동기 결과 핸들
  • get (블로킹), cancel, isDone

3. 한계

  • get 블로킹, 조합 어려움
  • → CompletableFuture (논블로킹 콜백, Phase 8)

📚 다음으로...

Unit 7.4 — ThreadPoolExecutor 내부 (★ 마스터)

이번 Unit에서 Future/Callable 을 봤다면, 다음은 ThreadPoolExecutor 내부 (★ 마스터, 면접 핵심).

  • corePoolSize / maximumPoolSize / keepAliveTime
  • 작업 추가 흐름 (core → 큐 → max → 거부)
  • workQueue
  • 마스터 Unit (50문항)

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 스레드 풀 종료

4주차 누적 진행

✅ Phase 1~6 (25 Unit, 1차 정점 완료)
🚀 Phase 7 — Executor (3/7 진행) ★ 2차 정점

총: 28/35 Unit
profile
Software Developer

0개의 댓글