Flux/Mono를 만들었다고 별도 스레드에서 도는 게 아님subscribe()를 호출한 스레드 — Scheduler를 명시적으로 넣기 전엔 스레드 전환이 일어나지 않음| Scheduler | 스레드 | 용도 |
|---|---|---|
immediate() |
현재 스레드 | 스케줄링 안 함(no-op) |
single() |
단일 재사용 스레드 | 가벼운 단일 스레드 작업 (newSingle()은 호출마다 전용) |
parallel() |
코어 수 고정 풀 | CPU 바운드·빠른 논블로킹 작업 |
boundedElastic() |
상한 탄력 풀(기본 코어×10, 최대 10만 작업 큐) | 블로킹 I/O·장시간 작업 격리 |
fromExecutorService(...) |
주어진 풀 | 기존 ExecutorService 재사용 |
parallel/single 스레드에서 block() 등 블로킹 API를 호출하면 IllegalStateException — 이런 스레드는 블로킹되면 안 되기 때문Scheduler 스레드에서 실행publishOn까지 적용 → 여러 번 놓아 구간마다 스레드를 바꿀 수 있음Scheduler s = Schedulers.newParallel("parallel", 4);
// publishOn: 놓은 지점 "이후"가 s에서 실행
Flux.range(1, 2)
.map(i -> 10 + i) // 구독한 스레드에서 실행
.publishOn(s) // 여기서 s로 전환
.map(i -> "value " + i); // s(parallel) 스레드에서 실행
// subscribeOn: 위치와 무관하게 구독/소스가 s에서 시작
Flux.range(1, 2)
.map(i -> 10 + i) // s(parallel) 스레드에서 실행
.subscribeOn(s) // 구독을 s로 이동 (위치 무관)
.map(i -> "value " + i); // s(parallel) 스레드에서 실행
| 영향 방향 | 위치 의존 | 대표 용도 | |
|---|---|---|---|
publishOn |
이후(downstream) | 놓은 지점부터 | 특정 구간만 다른 스레드로 |
subscribeOn |
구독·소스(upstream) | 위치 무관(소스에 가까운 것만) | 소스 방출 스레드 지정, 블로킹 소스 격리 |
parallel 스레드를 블로킹하면 소수의 스레드가 묶여 전체 처리량이 붕괴한다 (1단계)boundedElastic로 오프로드
Mono.fromCallable(() -> jdbcBlockingCall()) // 블로킹 호출을 Callable로 감싸고
.subscribeOn(Schedulers.boundedElastic()); // 전용 풀에서 실행 → 이벤트 루프 보호