F-LAB JAVA · 4주차 · Phase 1 · 동시성의 기초
🚀 4주차 시작 — 동시성의 세계 진입
이 Unit을 끝내면 다음을 답할 수 있어야 한다.
멀티태스킹 (Multitasking) 은 1개의 CPU 코어가 여러 작업을 번갈아 가며 (시분할) 실행하여 "동시 실행처럼" 보이게 하는 소프트웨어 기법이고, 멀티프로세싱 (Multiprocessing) 은 여러 CPU 코어가 실제로 동시에 작업을 실행하는 하드웨어 기반 방식이다.
시분할 (Time Sharing) 은 CPU 시간을 매우 잘게 쪼개 여러 프로그램에 빠르게 번갈아 할당하므로, 사람 눈에는 동시 실행으로 보인다 — 이를 동시성 (Concurrency) 이라 한다.
반면 멀티프로세싱은 물리적으로 여러 코어가 동시 수행하므로 병렬성 (Parallelism) 이다.
둘은 함께 사용 가능 — 현대 시스템은 멀티코어 (멀티프로세싱) 각각에서 멀티태스킹을 한다.
작업 전환 시 컨텍스트 스위칭 비용이 발생하므로, 무한정 작업을 늘리면 오히려 느려진다.
멀티태스킹 (1명의 요리사):
요리사 1명이 여러 요리를 번갈아
- 파스타 면 삶다가 → 소스 젓다가 → 다시 면 보다가
- 빠르게 전환하니 "동시에 하는 것처럼"
- 실제로는 한 순간에 1가지만
- 동시성 (Concurrency)
멀티프로세싱 (여러 요리사):
요리사 4명이 각자 다른 요리
- 요리사 A: 파스타
- 요리사 B: 스테이크
- 요리사 C: 샐러드
- 진짜 동시에 4가지
- 병렬성 (Parallelism)
함께 사용 (4명 + 각자 멀티태스킹):
요리사 4명, 각자 여러 요리 번갈아
- 현대 시스템의 모습
- 멀티코어 + 시분할
→ 멀티태스킹 = 번갈아 (동시성), 멀티프로세싱 = 진짜 동시 (병렬성).
1. 멀티태스킹의 정의와 메커니즘
2. 멀티프로세싱의 정의와 메커니즘
3. 시분할 (Time Sharing) 의 원리
4. 스케줄링의 역할
5. 동시성 vs 병렬성
6. 단일 코어에서의 "동시 실행"
7. 멀티태스킹 + 멀티프로세싱 함께
8. 실무에서의 의미
9. 면접 + 자기 점검
멀티태스킹 (Multitasking):
1개의 CPU 코어가 여러 작업 (태스크) 을
매우 빠르게 번갈아 가며 실행하는 기법.
기반:
- 소프트웨어 (OS 의 시분할 스케줄링)
- 1개 코어로도 가능
효과:
- 사람 눈에는 동시 실행처럼
- 실제론 한 순간 1가지
멀티태스킹의 동작:
시간 →
코어: [작업A][작업B][작업C][작업A][작업B]...
↑ ↑ ↑
10ms 10ms 10ms (예시)
- 작업 A 를 10ms 실행
- 작업 B 로 전환 (컨텍스트 스위칭)
- 작업 B 를 10ms 실행
- 작업 C 로 전환
- ...
매우 빠른 전환 (밀리초 단위)
→ 사람은 "동시 실행" 으로 인지
OS (운영체제) 가 멀티태스킹 관리:
1. 스케줄러 (Scheduler)
- 어떤 작업을 얼마나 실행할지 결정
2. 컨텍스트 스위칭 (Context Switching)
- 작업 A → B 전환 시 상태 저장/복원
3. 우선순위 (Priority)
- 중요한 작업 먼저
4. 시간 할당량 (Time Quantum/Slice)
- 각 작업에 주는 CPU 시간
멀티태스킹의 역사:
초기 컴퓨터 (배치 처리):
- 한 번에 1프로그램만
- 끝나야 다음
멀티프로그래밍:
- 여러 프로그램 메모리에
- I/O 대기 시 다른 프로그램
시분할 시스템 (Time Sharing):
- 여러 사용자가 동시 사용처럼
- 1960년대 (CTSS, Multics)
현대:
- 모든 OS 가 멀티태스킹
- Windows, Linux, macOS
단일 코어 시스템:
CPU 코어 1개
실행 중:
한 순간에 1개 스레드/프로세스만
멀티태스킹:
빠르게 전환하여 여러 작업 진행
→ 동시 실행처럼 보임
하지만:
진짜 동시는 아님 (동시성, 병렬성 X)
// ILIC 서버에서의 멀티태스킹
// 여러 요청을 1개 코어가 번갈아 처리 (단일 코어 가정)
@RestController
public class ShipmentController {
@GetMapping("/api/shipments/{id}")
public Shipment get(@PathVariable Long id) {
// 요청 1 처리 중...
// 잠시 후 요청 2 로 전환 (멀티태스킹)
// 다시 요청 1 로...
return service.findById(id);
}
}
// 현대 멀티코어 서버:
// 여러 코어가 각자 요청 처리 (멀티프로세싱)
// + 각 코어가 여러 요청 번갈아 (멀티태스킹)
멀티태스킹의 정의와 메커니즘은?
답:
1. 정의:
메커니즘:
OS 역할:
본질:
멀티프로세싱 (Multiprocessing):
여러 개의 CPU 코어가
실제로 동시에 작업을 실행하는 방식.
기반:
- 하드웨어 (다중 코어/CPU)
- 물리적 동시 실행
효과:
- 진짜 동시 실행
- 병렬성 (Parallelism)
멀티프로세싱의 동작:
시간 →
코어1: [작업A 계속 실행 ─────────]
코어2: [작업B 계속 실행 ─────────]
코어3: [작업C 계속 실행 ─────────]
코어4: [작업D 계속 실행 ─────────]
- 4개 코어가 각자 다른 작업
- 진짜 동시에
- 4배 처리 (이론상)
현대 CPU 의 구조:
CPU 패키지
├── 코어 1 (자체 ALU, 레지스터, L1/L2 캐시)
├── 코어 2
├── 코어 3
├── 코어 4
└── 공유 L3 캐시
각 코어가 독립적으로 실행
→ 진짜 병렬 처리
예시:
- Intel Core i7: 8코어
- Apple M3: 8코어
- 서버 CPU: 수십 코어
하이퍼스레딩 (SMT):
1개 물리 코어가 2개 논리 코어처럼.
원리:
- 코어의 유휴 자원 활용
- 1코어 = 2 스레드 동시 (논리적)
예시:
- 4코어 + 하이퍼스레딩 = 8 논리 코어
- Runtime.availableProcessors() = 8
주의:
- 논리 코어 ≠ 물리 코어 성능
- 2배 성능 X (보통 1.2~1.3배)
// 자바에서 코어 수 확인
int cores = Runtime.getRuntime().availableProcessors();
System.out.println("Available processors: " + cores);
// 물리 코어 또는 논리 코어 (하이퍼스레딩 포함)
// 활용 — 스레드 풀 크기 결정
int poolSize = Runtime.getRuntime().availableProcessors();
ExecutorService executor = Executors.newFixedThreadPool(poolSize);
// CPU 바운드 작업: 코어 수
// I/O 바운드 작업: 코어 수보다 많이
// ILIC 의 병렬 처리
public class ShipmentBatchProcessor {
private final int cores = Runtime.getRuntime().availableProcessors();
// 멀티프로세싱 활용 — 병렬 Stream
public void processBatch(List<Shipment> shipments) {
shipments.parallelStream() // 여러 코어 활용
.forEach(this::processExpensive);
// 4코어면 약 4배 빠름 (CPU 바운드 작업)
}
// 명시적 스레드 풀
public void processWithPool(List<Shipment> shipments) {
ExecutorService executor = Executors.newFixedThreadPool(cores);
try {
for (Shipment s : shipments) {
executor.submit(() -> processExpensive(s));
}
} finally {
executor.shutdown();
}
}
private void processExpensive(Shipment s) {
// CPU 무거운 작업
}
}
멀티프로세싱의 정의와 메커니즘은?
답:
1. 정의:
메커니즘:
멀티코어:
하이퍼스레딩:
확인:
시분할 (Time Sharing):
CPU 시간을 매우 작은 단위 (타임 슬라이스) 로 쪼개
여러 작업에 빠르게 번갈아 할당하는 기법.
목적:
- 멀티태스킹의 핵심
- 여러 작업 "동시 진행" 환상
타임 슬라이스 (Time Quantum):
각 작업에 할당되는 CPU 시간.
크기:
- 보통 수~수십 밀리초
- Linux: 동적 (1ms ~ 수백 ms)
너무 크면:
- 응답성 ↓ (다른 작업 오래 대기)
너무 작으면:
- 컨텍스트 스위칭 오버헤드 ↑
시분할의 동작 (타임 슬라이스 10ms 예시):
시간 (ms): 0 10 20 30 40 50
작업: [A ][B ][C ][A ][B ][C ]
└─┬┘
10ms 마다 전환
사람의 인지:
- 100ms (1초의 1/10) 안에
- A, B, C 가 여러 번 실행
- "동시에 진행되는 것처럼"
실제:
- 한 순간엔 1가지만
- 빠른 전환의 착시
선점형 (Preemptive):
- OS 가 강제로 작업 전환
- 타임 슬라이스 소진 시
- 현대 OS 표준
- 한 작업이 독점 불가
비선점형 (Non-preemptive / Cooperative):
- 작업이 자발적으로 양보
- 옛 시스템 (Windows 3.x 등)
- 한 작업이 양보 안 하면 멈춤
- 위험
자바의 yield():
- 비선점형 힌트 (자발적 양보)
- 보장 X (OS 가 결정)
"동시 실행" 의 환상:
비유 — 영화 필름:
- 영화는 정지 이미지 (프레임) 의 연속
- 초당 24~60 프레임
- 사람 눈은 연속 동작으로 인지
시분할:
- 작업들의 빠른 전환
- 사람 눈은 동시 실행으로 인지
핵심:
- 실제론 순차 (1가지씩)
- 빠르니 동시처럼
// 단일 코어 서버에서 여러 요청 처리 (시분할)
// 톰캣의 스레드 풀
// server.tomcat.threads.max=200 (기본)
// 200개 스레드가 시분할로 요청 처리
@Service
public class ShipmentService {
public Shipment process(Long id) {
// 이 메서드 실행 중
// 타임 슬라이스 소진 시 다른 요청으로 전환
// (멀티태스킹)
Shipment s = repository.findById(id);
// DB 조회 (I/O 대기) 중 다른 요청 처리
// → CPU 효율 ↑
return s;
}
}
시분할의 원리는?
답:
1. 정의:
타임 슬라이스:
선점형:
환상:
본질:
스케줄링 (Scheduling):
어떤 작업을 언제, 얼마나 실행할지
OS 의 스케줄러가 결정하는 것.
목적:
- CPU 효율 최대화
- 공정성
- 응답성
스케줄러가 결정하는 것:
1. 다음에 실행할 작업
- 우선순위
- 대기 시간
- 공정성
2. 실행 시간 (타임 슬라이스)
- 작업 특성
- 우선순위
3. 전환 시점
- 타임 슬라이스 소진
- I/O 대기
- 우선순위 높은 작업 도착
주요 스케줄링 알고리즘:
1. FCFS (First Come First Served)
- 먼저 온 순서
- 단순, 비효율
2. Round Robin
- 순환 할당
- 공정
3. Priority Scheduling
- 우선순위 기반
- 기아 (starvation) 가능
4. CFS (Completely Fair Scheduler)
- Linux 의 기본
- 공정성 중심
5. MLFQ (Multi-Level Feedback Queue)
- 여러 우선순위 큐
- 동적 조정
// 자바 스레드 우선순위
Thread t = new Thread(task);
t.setPriority(Thread.MAX_PRIORITY); // 10
t.setPriority(Thread.NORM_PRIORITY); // 5 (기본)
t.setPriority(Thread.MIN_PRIORITY); // 1
// 주의:
// - 우선순위는 힌트일 뿐
// - OS 스케줄러가 최종 결정
// - 플랫폼마다 동작 다름
// - 의존하면 안 됨
// yield - 양보 힌트
Thread.yield();
// "다른 스레드에 기회를" 힌트
// 보장 X
스케줄링 결정 → 컨텍스트 스위칭
1. 스케줄러: "작업 A 그만, 작업 B 실행"
2. 컨텍스트 스위칭:
- A 의 상태 저장 (레지스터, PC 등)
- B 의 상태 복원
3. 작업 B 실행
비용:
- 컨텍스트 스위칭은 오버헤드
- 잦으면 성능 ↓ (다음 Unit 1.4)
// 스레드 우선순위 — 신중히 사용
public class ShipmentScheduler {
public void startWorkers() {
// 중요 작업 (높은 우선순위 — 힌트)
Thread critical = new Thread(this::processCritical);
critical.setPriority(Thread.MAX_PRIORITY);
critical.start();
// 일반 작업
Thread normal = new Thread(this::processNormal);
normal.setPriority(Thread.NORM_PRIORITY);
normal.start();
// 백그라운드 (낮은 우선순위)
Thread background = new Thread(this::cleanup);
background.setPriority(Thread.MIN_PRIORITY);
background.setDaemon(true);
background.start();
}
// 실무: 우선순위보다 Executor + 적절한 풀 구성 권장
}
스케줄링의 역할은?
답:
1. 정의:
결정 사항:
알고리즘:
자바:
동시성 (Concurrency):
- 여러 작업을 번갈아 처리
- 논리적 동시 (실제론 순차)
- 단일 코어로도 가능
- 멀티태스킹
병렬성 (Parallelism):
- 여러 작업을 실제 동시 처리
- 물리적 동시
- 멀티 코어 필요
- 멀티프로세싱
Rob Pike (Go 언어 창시자):
"Concurrency is about dealing with lots of things at once.
Parallelism is about doing lots of things at once."
번역:
- 동시성: 여러 일을 다루는 것 (구조)
- 병렬성: 여러 일을 동시에 하는 것 (실행)
핵심:
- 동시성: 설계/구조 개념
- 병렬성: 실행 방식
동시성 (단일 코어):
코어: [A][B][A][B][A][B]
번갈아 처리
논리적 동시
병렬성 (멀티 코어):
코어1: [A ────────────]
코어2: [B ────────────]
실제 동시
물리적 동시
동시성 + 병렬성 (멀티 코어 + 멀티태스킹):
코어1: [A][C][A][C]
코어2: [B][D][B][D]
각 코어가 번갈아
+ 코어 간 병렬
동시성 (바리스타 1명):
주문 A 받고 → 주문 B 받고 → A 커피 만들고 → B 커피
- 1명이 여러 주문 다룸 (구조)
- 번갈아
병렬성 (바리스타 2명):
바리스타 1: 주문 A
바리스타 2: 주문 B
- 실제 동시
핵심:
- 동시성: 여러 주문을 어떻게 다룰지 (구조)
- 병렬성: 실제 몇 명이 동시에 (실행)
// 동시성 — 여러 작업 구조화
ExecutorService executor = Executors.newFixedThreadPool(4);
for (int i = 0; i < 100; i++) {
final int id = i;
executor.submit(() -> process(id));
}
// 100개 작업을 4 스레드로 처리 (동시성)
// 4코어면 병렬성도 (4개 동시 실행)
// 병렬성 — 명시적 병렬
List<Integer> result = numbers.parallelStream()
.map(this::heavyComputation)
.toList();
// 멀티 코어 활용 (병렬성)
동시성이 유효:
- I/O 바운드 작업
- 네트워크, DB, 파일
- 대기 시간 동안 다른 작업
- 단일 코어로도 효율 ↑
병렬성이 유효:
- CPU 바운드 작업
- 계산 집약적
- 멀티 코어 필수
- 작업 분할 가능
예:
- 웹 서버 (많은 요청): 동시성
- 이미지 처리 (계산): 병렬성
- 대용량 데이터 분석: 병렬성
public class ShipmentConcurrencyParallelism {
// 동시성 — I/O 바운드 (DB 조회 등)
public List<Shipment> fetchMany(List<Long> ids) {
ExecutorService executor = Executors.newFixedThreadPool(10);
// 10 스레드 (코어보다 많이 — I/O 대기 동안 효율)
try {
List<Future<Shipment>> futures = ids.stream()
.map(id -> executor.submit(() -> repository.findById(id)))
.toList();
return futures.stream()
.map(this::getResult)
.toList();
} finally {
executor.shutdown();
}
}
// 병렬성 — CPU 바운드 (계산)
public BigDecimal calculateTotalFreight(List<Shipment> shipments) {
return shipments.parallelStream() // 멀티 코어
.map(this::expensiveFreightCalculation)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
private Shipment getResult(Future<Shipment> f) {
try { return f.get(); }
catch (Exception e) { throw new RuntimeException(e); }
}
private BigDecimal expensiveFreightCalculation(Shipment s) {
// CPU 무거운 계산
return s.getWeight().multiply(BigDecimal.valueOf(1000));
}
}
동시성 vs 병렬성의 차이는?
답:
1. 동시성:
병렬성:
Rob Pike:
유효한 경우:
질문:
코어가 1개인데 어떻게 동시 실행처럼 보이나?
답:
멀티태스킹 (시분할).
빠르게 번갈아 → 동시 실행 환상.
단일 코어의 멀티태스킹:
1. 작업 A 실행 (10ms)
2. 컨텍스트 스위칭
3. 작업 B 실행 (10ms)
4. 컨텍스트 스위칭
5. 작업 A 실행 (10ms)
...
사람 인지:
- 1초에 A, B 가 각 50번 실행
- "동시 진행" 으로 느낌
실제:
- 한 순간 1가지
- 빠른 전환
멀티태스킹이 진짜 유용한 순간 — I/O 대기:
작업 A 가 DB 조회 (I/O):
- DB 응답 대기 (수십 ms)
- 이 동안 CPU 는 놀고 있음
멀티태스킹:
- A 가 대기하는 동안
- 작업 B 실행
- CPU 효율 ↑
핵심:
- I/O 대기 = CPU 유휴
- 그 시간에 다른 작업
- 단일 코어도 효율 ↑
멀티태스킹 없이 (순차):
코어: [A 계산][A DB 대기...][A 계산][B 계산]...
↑ CPU 놀고 있음 (낭비)
멀티태스킹 (효율):
코어: [A 계산][B 계산][A DB 완료 후][B DB 대기 중 C]...
↑ A 가 DB 대기하는 동안 B 실행
→ CPU 쉬지 않음
→ 처리량 ↑
단일 코어 + 멀티태스킹:
- 동시성 O
- 병렬성 X
- I/O 바운드에 효과적
- CPU 바운드는 한계
멀티 코어 + 멀티프로세싱:
- 동시성 O
- 병렬성 O
- CPU 바운드도 효과적
- 진짜 동시 실행
웹 서버 (단일 코어 가정):
요청 100개 동시 도착:
- 각 요청 = DB 조회 (I/O 대기 많음)
- 멀티태스킹으로 처리
- A 가 DB 대기 → B 처리 → C 처리...
- CPU 효율 ↑
- 100개를 1코어로도 처리 가능
핵심:
- 웹 요청은 대부분 I/O 바운드
- 단일 코어 + 멀티태스킹으로 충분히 많은 요청
- 멀티 코어면 더 좋음
// 단일 코어에서도 효율적인 비동기 I/O
public class ShipmentAsyncService {
// I/O 바운드 — 멀티태스킹 효과
public CompletableFuture<Shipment> fetchAsync(Long id) {
return CompletableFuture.supplyAsync(() -> {
// DB 조회 (I/O 대기)
// 이 동안 다른 작업 처리 (멀티태스킹)
return repository.findById(id);
});
}
// 여러 요청 동시 (단일 코어도 효율)
public CompletableFuture<List<Shipment>> fetchMany(List<Long> ids) {
List<CompletableFuture<Shipment>> futures = ids.stream()
.map(this::fetchAsync)
.toList();
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenApply(v -> futures.stream()
.map(CompletableFuture::join)
.toList());
}
}
단일 코어에서 동시 실행처럼 보이는 이유는?
답:
1. 멀티태스킹:
I/O 대기 활용:
단일 코어 효과:
본질:
질문:
멀티태스킹과 멀티프로세싱을 함께 쓸 수 있나?
답:
예! 현대 시스템의 표준.
멀티 코어 (멀티프로세싱)
+ 각 코어가 여러 작업 번갈아 (멀티태스킹)
현대 시스템 (4코어 + 멀티태스킹):
코어1: [A][E][A][E]... ← 멀티태스킹
코어2: [B][F][B][F]... ← 멀티태스킹
코어3: [C][G][C][G]... ← 멀티태스킹
코어4: [D][H][D][H]... ← 멀티태스킹
↑
코어 간 병렬 (멀티프로세싱)
8개 작업 (A~H):
- 4코어로 병렬 (멀티프로세싱)
- 각 코어가 2작업 번갈아 (멀티태스킹)
OS 의 작업 분배:
1. 작업을 코어에 할당
- 로드 밸런싱
- 코어 친화도 (affinity)
2. 각 코어에서 멀티태스킹
- 시분할
- 컨텍스트 스위칭
3. 작업 이동
- 한 코어가 바쁘면 다른 코어로
- work stealing 유사
자바 스레드 ↔ OS 스레드:
전통적 (1:1 모델):
- 자바 스레드 1개 = OS 스레드 1개
- OS 가 스케줄링
- 멀티 코어 활용
Virtual Thread (Java 21+):
- 다수 가상 스레드 = 소수 OS 스레드
- M:N 모델
- I/O 바운드에 효율
- 멀티태스킹의 자바 레벨 구현
이상적 스레드 수:
CPU 바운드 작업:
- 스레드 수 = 코어 수
- 더 많으면 컨텍스트 스위칭 낭비
I/O 바운드 작업:
- 스레드 수 > 코어 수
- I/O 대기 동안 다른 스레드
- 공식: 코어 수 × (1 + 대기시간/처리시간)
예:
4코어, I/O 대기 90%:
4 × (1 + 9) = 40 스레드 정도
public class ShipmentThreadConfig {
private final int cores = Runtime.getRuntime().availableProcessors();
// CPU 바운드 풀 (코어 수)
public ExecutorService cpuBoundPool() {
return Executors.newFixedThreadPool(cores);
// 계산 작업 (운임 계산 등)
}
// I/O 바운드 풀 (코어 수보다 많이)
public ExecutorService ioBoundPool() {
return Executors.newFixedThreadPool(cores * 4);
// DB 조회, API 호출 등
}
// Virtual Thread (Java 21+) — I/O 바운드 최적
public ExecutorService virtualThreadPool() {
return Executors.newVirtualThreadPerTaskExecutor();
// 수만 개 동시 I/O 작업 효율
}
}
멀티태스킹과 멀티프로세싱을 함께?
답:
1. 함께 가능:
현대 시스템:
OS 역할:
스레드 수:
// 작업 유형에 따른 풀 크기
// CPU 바운드 — 코어 수
int cpuPoolSize = Runtime.getRuntime().availableProcessors();
// I/O 바운드 — 더 많이
int ioPoolSize = Runtime.getRuntime().availableProcessors() * 4;
// 혼합 — 측정 후 조정
// Little's Law: 스레드 수 = 처리율 × 응답시간
스레드를 무한정 늘리면?
1. 메모리 부족
- 스레드 1개 ≈ 1MB 스택
- 1만 스레드 = 10GB
2. 컨텍스트 스위칭 폭증
- 전환 비용 ↑
- 실제 작업 시간 ↓
3. 성능 저하
- 코어 수보다 많으면
- 오히려 느려짐
결론:
- 적절한 풀 크기
- 무한 생성 X (Executor)
// I/O 바운드 — 동시성 (많은 스레드)
public List<Response> callManyApis(List<Request> requests) {
ExecutorService executor = Executors.newFixedThreadPool(50);
// I/O 대기 많으니 스레드 많이
// ...
}
// CPU 바운드 — 병렬성 (코어 수)
public List<Result> heavyCompute(List<Data> data) {
return data.parallelStream() // ForkJoinPool (코어 수)
.map(this::compute)
.toList();
}
"추측하지 말고 측정하라":
1. 프로파일링
- VisualVM, JProfiler
- 스레드 상태 확인
2. 벤치마크
- JMH
- 실제 성능 측정
3. 모니터링
- 운영 환경
- CPU, 메모리, 스레드 수
핵심:
- 동시성/병렬성 효과는 측정으로
- 무조건 병렬 X (오버헤드)
@Configuration
public class ConcurrencyConfig {
@Bean
public Executor cpuBoundExecutor() {
int cores = Runtime.getRuntime().availableProcessors();
return new ThreadPoolExecutor(
cores, cores,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
@Bean
public Executor ioBoundExecutor() {
int cores = Runtime.getRuntime().availableProcessors();
return new ThreadPoolExecutor(
cores * 2, cores * 8,
60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000),
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
}
@Service
public class ShipmentProcessingService {
private final Executor cpuExecutor;
private final Executor ioExecutor;
// CPU 바운드 — 운임 계산
@Async("cpuBoundExecutor")
public CompletableFuture<BigDecimal> calculateFreight(Shipment s) {
return CompletableFuture.completedFuture(expensiveCalc(s));
}
// I/O 바운드 — 외부 API
@Async("ioBoundExecutor")
public CompletableFuture<TrackingInfo> fetchTracking(String blNo) {
return CompletableFuture.completedFuture(externalApi.track(blNo));
}
}
실무에서의 의미는?
답:
1. 스레드 풀 크기:
과도한 스레드 위험:
선택:
측정:
| Q | 핵심 답변 |
|---|---|
| 멀티태스킹? | 1코어가 여러 작업 번갈아 (시분할) |
| 멀티프로세싱? | 여러 코어가 실제 동시 |
| 시분할? | CPU 시간 쪼개 번갈아 할당 |
| 동시성 vs 병렬성? | 번갈아 (논리) vs 동시 (물리) |
| 단일 코어 동시 실행? | 멀티태스킹 (환상) |
| 함께 사용? | 가능 (현대 표준) |
| 컨텍스트 스위칭? | 작업 전환 비용 |
| 스레드 수 결정? | CPU 코어 수 vs I/O 더 많이 |
| availableProcessors? | 코어 수 (논리 포함) |
| 우선순위? | 힌트, OS 가 결정 |
답:
답:
답:
답:
답:
1. 멀티태스킹 vs 멀티프로세싱
2. 동시성 vs 병렬성
3. 실무
이번 Unit에서 멀티태스킹/멀티프로세싱을 봤다면, 다음은 프로세스와 스레드의 정의와 메모리 구조.
🚀 Phase 1 — 동시성의 기초
✅ Unit 1.1 멀티태스킹 vs 멀티프로세싱 ← 여기
⏭ Unit 1.2 프로세스와 스레드
⏭ Unit 1.3 변수 종류와 메모리 위치
⏭ Unit 1.4 스케줄링 큐와 컨텍스트 스위칭
🚀 Phase 1 — 동시성의 기초 (1/4 진행)
총: 1/35 Unit
🚀 4주차 시작 — 동시성의 세계 진입