Unit 1.1 — 스레드를 많이 쓸 때의 함정

Psj·2026년 5월 26일

F-lab

목록 보기
155/240

Unit 1.1 — 스레드를 많이 쓸 때의 함정

F-LAB JAVA · 5주차 · Phase 1 · 스레드 풀의 필요성 재정리
🚀 5주차 시작 — Part A 동시성 마무리


📌 학습 목표

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

  • "스레드를 많이 쓸수록 빠를까?" 의 답은?
  • 컨텍스트 스위칭 오버헤드 란?
  • 스레드 수와 데드락 의 관계는?
  • 노는 스레드 (idle thread) 의 자원 낭비 는?
  • 스레드는 공짜가 아니다 의 의미는?
  • 멀티 프로세스보다 멀티 스레드 스위칭이 싼 이유는?
  • 노는 스레드가 CPU 에 부담 을 주는 이유는?
  • 적정 스레드 수 의 개념은?
  • 스레드 풀이 답인 이유는?

🎯 핵심 한 문장

스레드를 많이 쓸수록 항상 빠른 것은 아니며, 컨텍스트 스위칭 오버헤드·데드락 가능성·노는 스레드의 자원 낭비라는 3가지 함정 때문에 "스레드는 존재 자체로 비용" 이다.
컨텍스트 스위칭 오버헤드 — 스레드가 많아질수록 CPU 가 스레드를 번갈아 실행하기 위한 전환 비용 (레지스터 백업·복원, 캐시 무효화) 이 늘어나, 실제 작업보다 전환에 시간을 더 쓰게 된다.
데드락 가능성 — 스레드와 락이 많아질수록 서로의 자원을 기다리는 데드락이 발생할 확률이 높아진다.
노는 스레드의 자원 낭비 — 작업하지 않는 스레드도 스택 메모리 (기본 1MB) 를 차지하고 스케줄링 대상이 되어 비용을 발생시킨다.
결론적으로 스레드는 공짜가 아니므로, 무한정 생성하지 말고 스레드 풀로 개수를 제한하고 재사용 해야 한다 (Phase 1 의 주제).

비유 — 식당에 직원을 무한정 늘리면

스레드 = 식당 직원:

"직원 많을수록 빠를까?" → NO

함정 1 — 컨텍스트 스위칭:
  - 주방 좁은데 직원 100명
  - 서로 부딪히고 비켜주느라
  - 실제 요리보다 정리에 시간

함정 2 — 데드락:
  - 직원 A: 칼 들고 도마 기다림
  - 직원 B: 도마 들고 칼 기다림
  - 서로 영원히 대기

함정 3 — 노는 직원:
  - 일 없는 직원도 월급 (메모리)
  - 자리 차지 (스케줄링)
  - 매니저가 신경 써야 (오버헤드)

→ 직원은 공짜가 아니다
→ 적정 인원 (스레드 풀)

→ 스레드 많다고 빠른 게 아니다 (스위칭/데드락/노는 스레드), 공짜 아님.


🧭 9개 섹션 로드맵

1. "많을수록 빠를까?" 의 답
2. 함정 1 — 컨텍스트 스위칭
3. 함정 2 — 데드락 가능성
4. 함정 3 — 노는 스레드 낭비
5. 스레드는 공짜가 아니다
6. 멀티 프로세스 vs 멀티 스레드 스위칭
7. 적정 스레드 수
8. 스레드 풀이 답
9. 면접 + 자기 점검

1️⃣ "많을수록 빠를까?" 의 답

1.1 직관과 현실

직관:
  "스레드 많으면 → 병렬 ↑ → 빠름"

현실:
  "스레드 너무 많으면 → 오히려 느림"

이유:
  - 코어 수 한계
  - 스위칭 오버헤드
  - 자원 경쟁

1.2 코어 수 한계

코어 수 한계:

  코어 4개:
    - 동시 실행 = 최대 4개
    - 스레드 100개 → 25배 대기

  나머지 96개:
    - 대기 (스위칭 대상)
    - 자원만 차지

1.3 처리량 곡선

스레드 수 vs 처리량:

처리량
  │      ╭──────╮
  │     ╱        ╲___ (스위칭 오버헤드)
  │    ╱
  │   ╱
  └──────────────────→ 스레드 수
      최적점

  - 최적점까지: 처리량 ↑
  - 초과: 처리량 ↓ (오버헤드)

1.4 작업 유형 영향

작업 유형:

CPU 바운드:
  - 코어 수 정도가 최적
  - 초과 시 스위칭만

I/O 바운드:
  - 대기 많음
  - 코어보다 많이 가능
  - 단, 한계 있음

1.5 ILIC 의 맥락

@Service
public class ThreadCountTrap {
    
    // ❌ 무조건 많이 (역효과)
    public void processWrong(List<Shipment> shipments) {
        for (Shipment s : shipments) {
            new Thread(() -> process(s)).start();
            // 1만 건 = 1만 스레드
            // 코어 8개 → 스위칭 폭증
            // 오히려 느림
        }
    }
    
    // ✓ 적정 (스레드 풀)
    private final ExecutorService executor = 
        Executors.newFixedThreadPool(
            Runtime.getRuntime().availableProcessors());
    
    public void processRight(List<Shipment> shipments) {
        for (Shipment s : shipments) {
            executor.submit(() -> process(s));
            // 코어 수만큼 (최적)
        }
    }
    
    private void process(Shipment s) { }
}

1.6 자기 점검 답변

"스레드를 많이 쓸수록 빠를까?" 의 답은?

:
1. :

  • NO
  • 최적점 존재
  1. 이유:

    • 코어 수 한계
    • 스위칭 오버헤드
  2. 곡선:

    • 최적점까지 ↑
    • 초과 ↓
  3. 유형:

    • CPU: 코어 수
    • I/O: 더 많이 가능

2️⃣ 함정 1 — 컨텍스트 스위칭

2.1 컨텍스트 스위칭

컨텍스트 스위칭 (Context Switching):

  CPU 가 한 스레드에서
  다른 스레드로 전환하는 작업.

비용:
  - 레지스터 백업/복원
  - 캐시 무효화
  - 스케줄링

2.2 스위칭 비용

스위칭 시 일어나는 일:

1. 현재 스레드 상태 저장
   - 레지스터 → 메모리

2. 다음 스레드 상태 복원
   - 메모리 → 레지스터

3. 캐시 무효화
   - 캐시 미스 발생

4. 컨텍스트 전환
   - 스택, PC 카운터

2.3 스위칭 횟수

스위칭 횟수:

  스레드 ↑ → 스위칭 ↑

  코어 4개, 스레드 100개:
    - 25배 더 자주 전환
    - 작업보다 전환에 시간

→ 스레드 ↑ ≠ 처리량 ↑

2.4 캐시 영향

캐시 영향:

  스레드 전환 시:
    - 이전 스레드 캐시 무효
    - 새 스레드 캐시 채우기 (미스)
    - 메모리 접근 ↑

  잦은 전환:
    - 캐시 효율 ↓
    - 성능 저하

2.5 시각화

컨텍스트 스위칭:

스레드 적음 (효율):
  [작업A────][작업B────][작업A────]
  (긴 작업, 적은 전환)

스레드 많음 (비효율):
  [A][B][C][A][D][B][전환][전환]...
  (짧게 쪼개짐, 잦은 전환)
   ↑ 전환 비용 누적

2.6 ILIC 의 맥락

@Service
public class ContextSwitchingCost {
    
    private final int cores = Runtime.getRuntime().availableProcessors();
    
    // CPU 바운드 — 코어 수 (스위칭 최소)
    private final ExecutorService cpuPool = 
        Executors.newFixedThreadPool(cores);
    // 코어 수 = 스위칭 최소
    // 운임 계산 등 CPU 작업
    
    public BigDecimal calculate(Shipment shipment) {
        // CPU 작업은 코어 수만큼
        return freightCalculator.calculate(shipment);
    }
    
    // ❌ 과도한 스레드 (스위칭 폭증)
    public void overThreaded(List<Shipment> shipments) {
        ExecutorService tooMany = Executors.newFixedThreadPool(1000);
        // 코어 8개에 1000 스레드
        // → 스위칭 오버헤드 막대
        // → CPU 작업 비효율
    }
    
    private BigDecimal calculateFreight(Shipment s) { return s.getWeight(); }
}

2.7 자기 점검 답변

컨텍스트 스위칭 오버헤드란?

:
1. 정의:

  • 스레드 전환 비용
  1. 비용:

    • 레지스터 백업/복원
    • 캐시 무효화
  2. 횟수:

    • 스레드 ↑ → 스위칭 ↑
  3. 영향:

    • 작업보다 전환에 시간

3️⃣ 함정 2 — 데드락 가능성

3.1 데드락과 스레드 수

데드락과 스레드 수:

  스레드 많음 + 락 많음:
    - 자원 경쟁 ↑
    - 순환 대기 가능성 ↑
    - 데드락 확률 ↑

3.2 복잡도 증가

복잡도 증가:

  스레드 2개:
    - 상호작용 단순
    - 데드락 추적 쉬움

  스레드 100개:
    - 상호작용 복잡
    - 락 의존 얽힘
    - 데드락 추적 어려움

3.3 데드락 복습

데드락 (4주차 복습):

  4조건:
    - 상호 배제
    - 점유 대기
    - 비선점
    - 순환 대기

  스레드 ↑ → 순환 대기 가능성 ↑

3.4 진단 어려움

진단 어려움:

  스레드 많으면:
    - jstack 출력 방대
    - 데드락 찾기 어려움
    - 재현 어려움 (타이밍)

→ 스레드 적을수록 관리 쉬움

3.5 ILIC 의 맥락

@Service
public class DeadlockRisk {
    
    // 스레드 많을수록 데드락 위험 ↑
    
    private final ReentrantLock lockA = new ReentrantLock();
    private final ReentrantLock lockB = new ReentrantLock();
    
    // 스레드 풀로 제한 (데드락 관리 쉬움)
    private final ExecutorService pool = Executors.newFixedThreadPool(4);
    
    // 락 순서 일관 (데드락 방지, 4주차)
    public void transfer(ShipmentAccount from, ShipmentAccount to, BigDecimal amount) {
        ShipmentAccount first = from.id < to.id ? from : to;
        ShipmentAccount second = from.id < to.id ? to : from;
        
        first.lock.lock();
        try {
            second.lock.lock();
            try {
                from.balance = from.balance.subtract(amount);
                to.balance = to.balance.add(amount);
            } finally {
                second.lock.unlock();
            }
        } finally {
            first.lock.unlock();
        }
        // 스레드 적고 + 락 순서 일관 → 데드락 위험 ↓
    }
    
    static class ShipmentAccount {
        long id;
        ReentrantLock lock = new ReentrantLock();
        BigDecimal balance = BigDecimal.ZERO;
    }
}

3.6 자기 점검 답변

스레드 수와 데드락의 관계는?

:
1. 관계:

  • 스레드 ↑ → 데드락 ↑
  • 락 경쟁 ↑
  1. 복잡도:

    • 상호작용 복잡
    • 추적 어려움
  2. 진단:

    • jstack 방대
    • 재현 어려움
  3. 관리:

    • 적을수록 쉬움

4️⃣ 함정 3 — 노는 스레드 낭비

4.1 노는 스레드

노는 스레드 (idle thread):

  작업하지 않는 스레드도:
    - 스택 메모리 차지 (1MB)
    - 스케줄링 대상
    - 자원 낭비

4.2 메모리 낭비

메모리 낭비:

  노는 스레드도:
    - 스택 메모리 (기본 1MB)
    - 1000 노는 스레드 = 1GB
    - 작업 안 해도 차지

→ 메모리 압박

4.3 스케줄링 부담

스케줄링 부담:

  노는 스레드도:
    - 스케줄러가 고려
    - 큐에 존재
    - 스케줄링 오버헤드

→ 노는데도 비용

4.4 왜 CPU 부담

노는 스레드가 CPU 부담:

  - 스케줄러가 모든 스레드 관리
  - 노는 스레드도 상태 확인
  - 스위칭 후보
  - 메모리 관리 (GC 영향)

→ 존재 자체로 부담

4.5 ILIC 의 맥락

@Service
public class IdleThreadWaste {
    
    // ❌ 노는 스레드 많음 (낭비)
    public void wasteful() {
        // 1000 스레드 생성, 대부분 노는 중
        for (int i = 0; i < 1000; i++) {
            new Thread(() -> {
                try { Thread.sleep(Long.MAX_VALUE); } catch (Exception e) {}
                // 영원히 노는 스레드
                // 1MB × 1000 = 1GB 낭비
            }).start();
        }
    }
    
    // ✓ 풀 + keepAlive (노는 스레드 회수)
    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
        4,                              // core
        20,                             // max
        60L, TimeUnit.SECONDS,          // 노는 스레드 60초 후 회수
        new LinkedBlockingQueue<>(100)
    );
    // 피크 후 노는 스레드 정리 (20 → 4)
    // 메모리 절약
    
    public void efficient(Shipment shipment) {
        executor.submit(() -> process(shipment));
    }
    
    private void process(Shipment s) { }
}

4.6 자기 점검 답변

노는 스레드의 자원 낭비는?

:
1. 노는 스레드:

  • 작업 안 해도 비용
  1. 메모리:

    • 스택 1MB
    • 1000개 = 1GB
  2. 스케줄링:

    • 스케줄러 고려
    • 오버헤드
  3. 회수:

    • keepAlive (풀)

5️⃣ 스레드는 공짜가 아니다

5.1 핵심 메시지

스레드는 공짜가 아니다:

  존재 자체로 비용:
    - 생성 비용
    - 메모리 (스택)
    - 스케줄링
    - 스위칭

→ 무한 생성 X
→ 신중히 관리

5.2 비용 정리

스레드 비용 정리:

1. 생성 비용
   - OS 스레드, 초기화

2. 메모리
   - 스택 1MB

3. 스위칭
   - 전환 오버헤드

4. 스케줄링
   - 관리 부담

5. 데드락
   - 복잡도

5.3 트레이드오프

트레이드오프:

  스레드 적음:
    + 스위칭 적음
    + 관리 쉬움
    - 병렬성 ↓

  스레드 많음:
    + 병렬성 ↑ (한계까지)
    - 스위칭 ↑
    - 자원 ↑

→ 적정점 찾기

5.4 실무 원칙

실무 원칙:

  "스레드를 직접 만들지 마라.
   ExecutorService 를 써라.
   풀 크기는 신중히 정하라."

  - 재사용 (생성 비용)
  - 개수 제한 (자원)
  - 적정 크기 (성능)

5.5 ILIC 의 맥락

@Service
public class ThreadNotFree {
    
    // 스레드 비용 인식 → 풀 사용
    private final int cores = Runtime.getRuntime().availableProcessors();
    
    // CPU 작업: 코어 수
    private final ExecutorService cpuPool = 
        Executors.newFixedThreadPool(cores);
    
    // I/O 작업: 더 많이 (대기 고려)
    private final ExecutorService ioPool = 
        Executors.newFixedThreadPool(cores * 4);
    
    public BigDecimal calculate(Shipment shipment) {
        // CPU → cpuPool
        try {
            return cpuPool.submit(() -> 
                freightCalculator.calculate(shipment)).get();
        } catch (Exception e) {
            return BigDecimal.ZERO;
        }
    }
    
    public TrackingInfo fetchTracking(String blNo) {
        // I/O → ioPool
        try {
            return ioPool.submit(() -> trackingApi.fetch(blNo)).get();
        } catch (Exception e) {
            return null;
        }
    }
    
    private BigDecimal calculateFreight(Shipment s) { return s.getWeight(); }
    record TrackingInfo() {}
}

5.6 자기 점검 답변

스레드는 공짜가 아니다의 의미는?

:
1. 핵심:

  • 존재 자체로 비용
  1. 비용:

    • 생성/메모리/스위칭
    • 스케줄링/데드락
  2. 트레이드오프:

    • 적음 vs 많음
    • 적정점
  3. 원칙:

    • 풀 사용, 크기 신중

6️⃣ 멀티 프로세스 vs 멀티 스레드 스위칭

6.1 차이

프로세스 vs 스레드 스위칭:

프로세스 스위칭:
  - 메모리 공간 전환 (무거움)
  - 페이지 테이블 교체
  - TLB 무효화

스레드 스위칭:
  - 같은 메모리 공유 (가벼움)
  - 레지스터/스택만
  - 메모리 공간 유지

6.2 왜 스레드가 싼가

스레드 스위칭이 싼 이유:

  같은 프로세스 내 스레드:
    - 메모리 공간 공유
    - 페이지 테이블 그대로
    - TLB 유지
    - 레지스터/스택만 전환

→ 메모리 공간 전환 X
→ 가벼움

6.3 메모리 공유

메모리 공유:

스레드 (공유):
  - 힙, 메서드 영역 공유
  - 스택만 개별

  → 전환 시 공유 부분 유지
  → 가벼운 전환

프로세스 (독립):
  - 메모리 완전 독립
  - 전환 시 전체 교체
  → 무거운 전환

6.4 트레이드오프

공유의 트레이드오프:

스레드 (공유):
  + 가벼운 스위칭
  + 통신 빠름 (공유 메모리)
  - 동기화 필요 (경쟁)
  - 한 스레드 오류 → 전체

프로세스 (독립):
  + 안전 (격리)
  - 무거운 스위칭
  - 통신 비쌈 (IPC)

6.5 ILIC 의 맥락

@Service
public class ProcessVsThreadSwitching {
    
    // 스레드 — 같은 프로세스 (가벼운 스위칭)
    private final ExecutorService pool = Executors.newFixedThreadPool(8);
    
    // 공유 메모리 (스레드 간 통신 빠름)
    private final ConcurrentHashMap<Long, Shipment> sharedCache = 
        new ConcurrentHashMap<>();
    
    public void process(Shipment shipment) {
        pool.submit(() -> {
            // 같은 힙 메모리 접근 (공유)
            sharedCache.put(shipment.getId(), shipment);
            // 스레드 간 통신 = 공유 메모리 (빠름)
            // 단, 동기화 필요 (ConcurrentHashMap)
        });
    }
    
    // 스레드 스위칭이 가벼워 멀티스레드 선택
    // (멀티 프로세스보다 효율)
}

6.6 자기 점검 답변

멀티 프로세스보다 멀티 스레드 스위칭이 싼 이유는?

:
1. 차이:

  • 프로세스: 메모리 공간 전환
  • 스레드: 레지스터/스택만
  1. 이유:

    • 메모리 공유
    • 페이지 테이블 유지
  2. 공유:

    • 힙 공유, 스택 개별
  3. 트레이드오프:

    • 가벼움 vs 동기화 필요

7️⃣ 적정 스레드 수

7.1 적정 수의 개념

적정 스레드 수:

  작업 유형에 따라 다름:
    - CPU 바운드
    - I/O 바운드

7.2 CPU 바운드

CPU 바운드:

  계산 위주 (CPU 사용):
    - 적정 = 코어 수 (+1)
    - 더 많으면 스위칭만

공식:
  N(threads) = N(cores) + 1

7.3 I/O 바운드

I/O 바운드:

  대기 위주 (네트워크, 디스크):
    - 대기 중 다른 작업 가능
    - 코어보다 많이

공식:
  N = N(cores) × (1 + 대기시간/계산시간)

7.4 측정 기반

측정 기반:

  공식은 출발점:
    - 부하 테스트
    - 모니터링
    - 튜닝

  실측 > 공식

7.5 Tomcat 예시

Tomcat maxThreads:

  기본값: 200
  - 동시 처리 요청 수
  - I/O 바운드 (웹 요청)
  - 너무 크면 메모리/스위칭
  - 너무 작으면 처리량 ↓

→ 워크로드에 맞게 조정

7.6 ILIC 의 맥락

@Configuration
public class OptimalThreadCount {
    
    private final int cores = Runtime.getRuntime().availableProcessors();
    
    // CPU 바운드 (운임 계산)
    @Bean("cpuPool")
    public ExecutorService cpuPool() {
        return Executors.newFixedThreadPool(cores + 1);
        // 코어 + 1
    }
    
    // I/O 바운드 (외부 API)
    @Bean("ioPool")
    public ExecutorService ioPool() {
        // 대기 90%, 계산 10% 가정
        // N = cores × (1 + 0.9/0.1) = cores × 10
        return Executors.newFixedThreadPool(cores * 10);
    }
    
    // 측정 후 조정 권장
}

7.7 자기 점검 답변

적정 스레드 수의 개념은?

:
1. 작업 유형:

  • CPU 바운드
  • I/O 바운드
  1. CPU:

    • 코어 + 1
  2. I/O:

    • 코어 × (1 + 대기/계산)
  3. 측정:

    • 공식은 출발점
    • 튜닝

8️⃣ 스레드 풀이 답

8.1 문제 → 해결

문제 → 스레드 풀:

생성 비용 ↑ → 재사용
무한 생성 위험 → 개수 제한
자원 낭비 → idle 회수

= Executor 프레임워크 (4주차)

8.2 재사용

재사용:

  스레드 풀:
    - 미리 생성
    - 작업마다 재사용
    - 생성 비용 1회

→ 스위칭 함정 + 생성 비용 해결

8.3 개수 제한

개수 제한:

  최대 수 제한:
    - 무한 생성 방지
    - 자원 보호
    - 적정 동시성

→ 스위칭/데드락 함정 완화

8.4 idle 회수

idle 회수:

  keepAliveTime:
    - 노는 스레드 정리
    - core 초과분
    - 메모리 절약

→ 노는 스레드 함정 해결

8.5 실무 결론

실무 결론:

  스레드 직접 생성 X
  ExecutorService 사용
  풀 크기 신중

  - 재사용
  - 제한
  - 적정 크기
  - idle 회수

8.6 ILIC 의 맥락

@Service
public class ThreadPoolAnswer {
    
    // 3가지 함정 해결
    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
        Runtime.getRuntime().availableProcessors(),  // core (적정)
        Runtime.getRuntime().availableProcessors() * 2,  // max (제한)
        60L, TimeUnit.SECONDS,                        // idle 회수
        new LinkedBlockingQueue<>(1000),
        new ThreadPoolExecutor.CallerRunsPolicy()
    );
    // - 재사용 (생성 비용)
    // - 제한 (무한 생성, 스위칭)
    // - idle 회수 (노는 스레드)
    
    public void process(Shipment shipment) {
        executor.submit(() -> doProcess(shipment));
    }
    
    @PreDestroy
    public void shutdown() {
        executor.shutdown();
        try {
            if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
    
    private void doProcess(Shipment s) { }
}

8.7 자기 점검 답변

스레드 풀이 답인 이유는?

:
1. 문제 해결:

  • 생성 비용 → 재사용
  • 무한 생성 → 제한
  • 낭비 → idle 회수
  1. 3함정 대응:

    • 스위칭/데드락/노는 스레드
  2. 실무:

    • ExecutorService
  3. 결론:

    • 직접 생성 X

9️⃣ 면접 + 자기 점검

9.1 면접 단골 질문 매핑

Q핵심 답변
많을수록 빠른가?NO (최적점)
함정 3가지?스위칭/데드락/노는 스레드
컨텍스트 스위칭?전환 비용
데드락 관계?스레드 ↑ → 위험 ↑
노는 스레드?메모리/스케줄링 낭비
공짜 아님?존재 자체 비용
프로세스 vs 스레드 스위칭?메모리 공유 (가벼움)
적정 수?CPU 코어+1, I/O 더 많이
스레드 풀?재사용/제한/회수
Tomcat maxThreads?기본 200

9.2 자기 점검 체크리스트

많을수록 빠른가

  • NO
  • 최적점

함정

  • 스위칭
  • 데드락
  • 노는 스레드

스위칭

  • 비용
  • 캐시

공짜 아님

  • 비용 인식

프로세스 vs 스레드

  • 메모리 공유

적정 수

  • CPU/IO

스레드 풀

9.3 추가 심화 질문

Q1: 하이퍼스레딩과 스레드 수?

답:

  • 물리 코어 × 2 (논리 코어)
  • availableProcessors() = 논리 코어
  • CPU 바운드는 논리 코어 기준
  • 단, 효율은 물리 코어 가까움

Q2: Virtual Thread 와 함정?

답:

  • Virtual Thread (Java 21+)
  • 경량 (스위칭 저렴)
  • 노는 스레드 비용 적음
  • I/O 바운드 함정 완화

Q3: 스위칭 비용 측정?

답:

  • vmstat (cs 컬럼)
  • perf
  • 스레드 수 vs 처리량 벤치마크
  • 최적점 찾기

Q4: 코어 수 확인?

답:

  • Runtime.getRuntime().availableProcessors()
  • 논리 코어 수
  • 컨테이너는 cgroup 제한 주의

Q5: CPU vs I/O 바운드 판단?

답:

  • CPU 사용률 모니터링
  • CPU 100% → CPU 바운드
  • CPU 낮고 대기 → I/O 바운드
  • 프로파일링

🎯 핵심 요약 — 3줄 정리

1. 많을수록 빠른가

  • NO (최적점 존재)
  • 코어 수 한계

2. 3가지 함정

  • 컨텍스트 스위칭 오버헤드
  • 데드락 가능성
  • 노는 스레드 자원 낭비

3. 결론

  • 스레드는 공짜가 아니다
  • 스레드 풀 (재사용/제한/회수)

📚 다음으로...

Unit 1.2 — 컨텍스트 스위칭의 진짜 비용

이번 Unit에서 스레드의 함정을 봤다면, 다음은 컨텍스트 스위칭의 진짜 비용 (상세).

  • 스위칭 시 일어나는 일 (레지스터/캐시)
  • 스위칭 횟수 = 스레드 수 비례
  • 노는 스레드도 스위칭 대상

Phase 1 진행 상황

🚀 Phase 1 — 스레드 풀의 필요성 재정리
  ✅ Unit 1.1 스레드를 많이 쓸 때의 함정 ← 여기
  ⏭ Unit 1.2 컨텍스트 스위칭의 진짜 비용
  ⏭ Unit 1.3 스레드 풀이라는 답

5주차 누적 진행

🚀 Part A — 동시성 마무리
  Phase 1 — 스레드 풀 필요성 (1/3)
⏭ Part B — 토비의 스프링

총: 1/26 Unit
profile
Software Developer

0개의 댓글