멀티테스킹(Multitasking)이란?
운영체제가 여러 작업(Task, 프로세스)을 거의 동시에 수행하도록 보여주는 기술입니다.
실제로는 CPU가 매우 빠르게 작업을 전환(컨텍스트 스위칭)해서 사람 눈에는 동시에 돌아가는 것처럼 보입니다.
"여러 작업(Task, 프로세스)"이란?
보통은 여러 프로세스, 또는 프로세스 안의 여러 스레드를 의미합니다.
예를 들어:
이 각각이 "작업(Task)"이며 운영체제가 이들을 번갈아가며 실행해줍니다.
CPU가 1개인데 동시에 어떻게 해?
실제론 동시에 실행하는 것이 아니라 빠르게 전환해서 동시에 실행되는 것처럼 보이게 하는 거예요.
이걸 시분할(Time-sharing) 방식이라고 합니다.
참고: CPU에 어떤 프로그램이 얼마만큼 실행될지는 운영체제가 결정하는데 이것이 스케줄링(Scheduling)입니다. 이때 단순히 시간으로만 작업을 분할하지는 않고, CPU를 최대한 활용할 수 있는 다양한 우선순위와 최적화 기법을 사용합니다. 운영체제가 스케줄링을 수행하고, CPU를 최대한 사용하면서 작업이 골고루 수행될 수 있게 최적화한다는 정도로 이해하면 충분합니다.
참고: CPU 안에는 실제 연산을 처리할 수 있는 코어라는 부품이 있습니다. 과거에는 하나의 CPU 안에 보통 하나의 코어만 들어있었습니다. 그래서 CPU와 코어를 따로 분리해서 이야기하지 않았습니다. 최근에는 하나의 CPU 안에 보통 2개 이상의 코어가 들어있습니다.
멀티테스킹의 구현 방식은?
운영체제는 멀티테스킹을 프로세스 기반 혹은 스레드 기반으로 구현할 수 있습니다.
CPU가 여러 개면 멀티테스킹은 어떻게 돼?
CPU가 여러 개면, 실제로 여러 작업이 동시에 실행됩니다.
즉, 멀티테스킹은 싱글 CPU 환경에서는 시분할 방식을, 멀티 CPU 환경에서는 실제 병렬 처리(멀티프로세싱)를 사용하여 더 효율적으로 실행돼요.
그러니까 멀티테스킹은 CPU 수에 관계없이 가능한 개념입니다.
멀티테스킹 요약 정리
| 항목 | 설명 |
|---|---|
| 정의 | OS가 여러 작업(Task)을 동시에 처리하는 것처럼 보이게 하는 기술 |
| 전제 조건 | CPU 1개든 여러 개든 상관없음 |
| 방식 | 시분할 방식 + 컨텍스트 스위칭 |
| 하위 구성 방식 | 프로세스 기반, 스레드 기반 멀티테스킹 |
| 실제 병렬 여부 | CPU 1개면 논리적 병렬, CPU 여러 개면 물리적 병렬도 가능 |
멀티프로세싱(Multiprocessing)이란?
하나의 컴퓨터 시스템에서 두 개 이상의 CPU(또는 코어)를 활용하여 여러 작업(프로세스)을 진짜로 동시에 병렬 처리하는 것입니다.
즉, 단순히 "동시에 실행되는 것처럼 보이게 하는" 게 아니라, 물리적으로 동시에 여러 작업을 수행하는 방식이에요.
멀티테스킹과 뭐가 달라?
| 항목 | 멀티테스킹 | 멀티프로세싱 |
|---|---|---|
| 핵심 | "동시 실행처럼 보이게" | "실제로 동시에 실행" |
| CPU 수 | 1개 이상 | 반드시 2개 이상 필요 |
| 예 | 하나의 CPU가 음악/문서 번갈아 실행 | 2개의 CPU가 각자 음악, 문서를 동시에 실행 |
즉, 멀티프로세싱은 멀티테스킹을 더 강력하게 만든 물리적 실현이라고 볼 수 있어요.
멀티프로세싱이 중요한 이유
어떤 상황에서 쓰이나?
멀티프로세싱 단점
멀티프로세싱 요약
| 항목 | 설명 |
|---|---|
| 정의 | 여러 개의 CPU/코어를 활용해 여러 작업을 병렬로 처리 |
| 전제 조건 | 반드시 2개 이상의 CPU 또는 멀티코어 |
| 처리 대상 | 독립된 프로세스 단위 |
| 실제 병렬 여부 | 예, 물리적으로 동시에 실행 |
| 장점 | 성능 향상, 안정성 증가 |
| 단점 | 자원 사용 큼, 통신 비용 발생 |
멀티스레딩(Multithreading)이란?
하나의 프로세스 내에서 여러 스레드(Thread)를 동시에 실행하는 방식입니다.
여기서 스레드(Thread)란,
멀티스레딩은 왜 사용하는 거야?
하나의 프로그램 안에서 여러 작업을 동시에 수행하기 위해서예요.
예를 들어:
멀티테스킹/멀티프로세싱이랑 뭐가 달라?
| 항목 | 멀티테스킹 | 멀티프로세싱 | 멀티스레딩 |
|---|---|---|---|
| 실행 단위 | 여러 프로세스 또는 스레드 | 여러 프로세스 | 하나의 프로세스 내 여러 스레드 |
| 자원 공유 | 없음 또는 제한적 공유 | 독립적 | 코드/데이터/힙 공유 (스택만 독립) |
| 생성/전환 비용 | 중간 | 높음 | 낮음 |
| 안정성 | 중간 | 높음 | 낮음 (하나 죽으면 전체 영향 가능) |
멀티스레딩은 진짜 동시에 실행되나?
→ 즉, 멀티스레딩은 멀티테스킹 구조 안에서도, 멀티프로세싱 구조 안에서도 함께 사용될 수 있어요.
단점도 있어?
멀티스레딩 요약
| 항목 | 설명 |
|---|---|
| 정의 | 하나의 프로세스 내에서 여러 스레드를 동시에 실행 |
| 실행 단위 | 스레드 (Thread) |
| 자원 공유 | 코드/힙/데이터는 공유, 스택은 독립 |
| 실제 병렬 여부 | 멀티코어면 가능, 싱글 코어면 논리적 병렬 |
| 장점 | 빠른 실행, 자원 효율적 사용 |
| 단점 | 동기화 복잡성, 안정성 낮음 |
멀티테스킹 vs 멀티프로세싱 vs 멀티스레딩 – 최종 요약표
| 항목 | 멀티테스킹 | 멀티프로세싱 | 멀티스레딩 |
|---|---|---|---|
| 💡 정의 | OS가 여러 작업을 동시에 처리하는 방식 | 여러 CPU(또는 코어)로 여러 프로세스를 병렬 실행 | 하나의 프로세스 내에서 여러 스레드를 동시에 실행 |
| 🧩 실행 단위 | 프로세스 또는 스레드 | 프로세스 | 스레드 (프로세스 내부) |
| ⚙️ 하드웨어 전제 | CPU 1개 이상 | CPU 2개 이상 필수 | CPU 1개 이상 (멀티코어면 진짜 병렬 가능) |
| 🔁 실제 병렬 처리 여부 | CPU 1개면 논리적, 여러 개면 물리적 병렬 가능 | 물리적 병렬 | 논리적 or 물리적 병렬 (멀티코어일 때) |
| 🧠 자원 공유 | 없음 또는 제한적 | 없음 (프로세스 간 메모리 독립) | 코드/힙/데이터 공유, 스택은 개별 |
| 📉 오버헤드 | 중간 | 큼 (프로세스 생성/통신 비용) | 작음 (스레드 전환이 가볍고 빠름) |
| ⚠️ 안정성 | 중간 | 높음 (프로세스 간 독립) | 낮음 (스레드 오류 시 전체 프로세스 영향) |
| 🧪 예시 | 음악 재생 + 문서 편집 | 브라우저의 탭마다 별도 프로세스로 실행 | 서버가 하나의 프로세스 안에서 다중 요청 처리 |
| 🔗 관계 | 상위 개념 | 멀티테스킹의 하위 구현 방식 | 멀티테스킹의 하위 구현 방식 |
프로세스(Process)는 실행 중인 프로그램을 의미해요.
예: 크롬을 두 번 실행하면 서로 독립된 두 개의 프로세스가 만들어집니다.
프로세스는 "독립적"이라고 해?
프로세스의 예시
프로세스 간 통신
어렵습니다.
프로세스 요약
| 항목 | 설명 |
|---|---|
| 정의 | 실행 중인 프로그램, OS가 관리하는 독립된 작업 단위 |
| 자원 관리 | 독립된 메모리 공간을 가짐 (코드, 힙, 스택 등) |
| 장점 | 안정적, 서로 영향 없음 |
| 단점 | 생성/전환 비용 큼, 통신 복잡 |
| 예시 | 워드, 크롬, 음악 앱 각각이 하나의 프로세스 |
스레드(Thread)가 뭐야?
스레드는 프로세스 내부에서 실행되는 가장 작은 실행 단위예요.
즉, 스레드는 프로세스 안에서 일하는 작업자들이라고 보면 됩니다.
왜 스레드를 쓰는 거야?
스레드들은 자원을 공유한다고?
맞습니다. 스레드는 같은 프로세스에 소속되기 때문에
장점은 뭐야?
단점은?
스레드 예시
요약
| 항목 | 설명 |
|---|---|
| 정의 | 프로세스 내부에서 실행되는 최소 단위의 실행 흐름 |
| 자원 구조 | 코드/힙/데이터는 공유, 스택은 개별 |
| 장점 | 빠름, 통신 비용 없음, 응답성 향상 |
| 단점 | 동기화 필요, 안정성 낮음 |
| 예시 | 서버 요청 처리, 게임 내 병렬 처리 |
프로세스 vs 스레드 – 비교 정리
| 항목 | 프로세스(Process) | 스레드(Thread) |
|---|---|---|
| 💡 정의 | 실행 중인 프로그램, OS가 관리하는 독립 단위 | 프로세스 내에서 실행되는 가장 작은 실행 단위 |
| 🧩 실행 단위 | 전체 프로그램 | 작업 내의 세부 흐름 |
| 📦 자원 구조 | 메모리 영역 모두 독립 | 코드/힙/데이터 공유, 스택만 독립 |
| 🔁 전환 비용 | 높음 (무거움) | 낮음 (가벼움) |
| 🔌 통신 방식 | IPC 필요 (pipe, socket 등) | 공유 메모리로 직접 접근 가능 |
| 🧱 안정성 | 높음 (하나 죽어도 다른 프로세스 unaffected) | 낮음 (하나의 스레드 오류로 전체 프로세스 영향 가능) |
| ⚠️ 동기화 이슈 | 없음 또는 낮음 | 있음 (race condition, deadlock 등 주의 필요) |
| 🧪 예시 | 워드, 크롬, 음악 앱 | 게임의 입력/렌더링/사운드 처리 스레드 |
프로세스는 실행 중인 독립 프로그램이고, 스레드는 그 안에서 동시에 일하는 실행 흐름입니다. 프로세스는 실행 환경과 자원을 제공하는 컨테이너 역할을 하고, 실제 CPU를 사용해서 코드를 하나하나 실행하는 것은 스레드입니다.
💡 정리 비유
컴퓨터는 동시에 수많은 스레드를 실행해야 합니다.
하지만 실제 CPU 코어 수는 제한되어 있으므로, 운영체제가 누가 먼저 CPU를 사용할지 결정해야 합니다.
→ 이 때 사용하는 것이 바로 스케줄링(Scheduling)입니다.
스레드(Thread) 복습
스레드 상태 (Thread Lifecycle) – 자바/OS 공통
[NEW] → [RUNNABLE] → [RUNNING] → [TERMINATED]
↓ ↑
[WAITING], [BLOCKED], [TIMED_WAITING]
| 상태 | 설명 |
|---|---|
| NEW | 스레드 객체 생성되었지만 아직 시작 안 함 |
| RUNNABLE | 실행 가능 상태 (CPU 할당 대기) |
| RUNNING | CPU가 할당되어 실제 실행 중 |
| BLOCKED | 다른 락(lock)을 기다리는 중 |
| WAITING | notify 등 외부 신호를 기다림 |
| TIMED_WAITING | 일정 시간 동안 대기 (ex. sleep(1000)) |
| TERMINATED | 실행 종료 |
스케줄링이란?
스레드가 RUNNABLE 상태에 있을 때, CPU를 어떤 순서로 할당할지 결정하는 정책입니다.
운영체제 커널이 이 역할을 수행하고, Java에서도 스케줄러 영향을 받습니다.
✅ 4. 주요 스케줄링 알고리즘 (OS 관점)
| 알고리즘 | 설명 |
|---|---|
| FCFS (선입선출) | 먼저 대기한 스레드부터 실행 |
| SJF (Shortest Job First) | 실행 시간이 가장 짧은 스레드 우선 |
| Round Robin | 시간 할당량(Quantum)을 정해 순환 처리 |
| Priority Scheduling | 우선순위가 높은 스레드 우선 |
| Multilevel Queue | 우선순위 그룹별로 큐 나눠서 처리 |
대부분의 OS(리눅스, 윈도우)는 우선순위 기반 + 라운드로빈을 조합한 방식을 사용합니다.
자바에서의 스레드 스케줄링
자바는 운영체제의 스케줄링 정책에 의존합니다. JVM이 직접 스케줄링하지 않아요!
Thread thread = new Thread(() -> {
// 실행할 코드
});
thread.setPriority(Thread.MAX_PRIORITY); // 우선순위 설정
setPriority() 메서드로 우선순위 설정 가능하지만,즉, 자바에서 스레드의 실행 순서를 강제하는 것은 권장되지 않으며 비결정적입니다.
스케줄링 관련 자바 주요 키워드
| 키워드/메서드 | 설명 |
|---|---|
Thread.sleep(ms) | 현재 스레드를 TIMED_WAITING 상태로 만듬 |
wait() / notify() | 조건 동기화 → WAITING/NOTIFY 흐름 |
join() | 다른 스레드가 종료될 때까지 대기 |
yield() | CPU를 양보하고 다시 RUNNABLE 상태로 감 |
스케줄링 요약
| 항목 | 설명 |
|---|---|
| 스레드 실행 상태 | NEW → RUNNABLE → RUNNING → 종료 |
| 스케줄링 필요 이유 | CPU 수보다 많은 스레드를 관리해야 해서 |
| 스케줄링 주체 | 운영체제 커널 (JVM은 따름) |
| 주요 정책 | Round Robin, Priority, FCFS 등 |
| 자바에서 제어 가능? | setPriority()는 힌트일 뿐, 보장 X |
🔑 핵심 문장
운영체제는 수많은 스레드를 효율적으로 실행하기 위해 스케줄링 알고리즘을 사용하며,
자바는 이 시스템의 흐름 안에서 스레드를 생성하고 조절하지만, 실행 순서를 직접 통제할 수는 없습니다.
운영체제가 현재 실행 중인 프로세스 또는 스레드의 상태(Context)를 저장하고,
다른 프로세스나 스레드의 상태를 복원하여 CPU 실행 대상을 전환하는 것입니다.
👉 "CPU 실행 주체를 바꾸는 일"
👉 "이전 실행 흐름은 멈추고, 새로운 실행 흐름으로 교체"
컨텍스트 스위칭이 왜 필요한가?
현대 컴퓨터는 멀티태스킹을 수행해야 합니다.
어떤 정보(Context)를 저장/복원하나?
| 저장 대상 | 예시 |
|---|---|
| CPU 레지스터 상태 | PC(Program Counter), 레지스터 값 등 |
| 메모리 맵 정보 | 어떤 메모리 영역을 사용하는지 |
| 프로세스 상태 | RUNNING → READY or WAITING |
| 스택 포인터 | 함수 호출의 위치, 지역 변수 |
| 스케줄링 정보 | 우선순위, 마지막 실행 시간 등 |
→ 이걸 모두 저장해야 다시 돌아왔을 때 정확히 이어서 실행할 수 있어요.
어떤 상황에서 발생할까?
sleep, wait)비용은 얼마나 들까?
컨텍스트 스위칭은 무료가 아닙니다.
| 항목 | 비용 설명 |
|---|---|
| 저장/복원 오버헤드 | 레지스터, 메모리 매핑, 캐시 무효화 등 |
| CPU 캐시 손실 | 다른 작업이 오면 캐시가 밀려나 성능 저하 |
| 커널 모드 전환 | 사용자 모드 ↔ 커널 모드 오버헤드 발생 |
한 번의 컨텍스트 스위칭은 수백~수천 나노초가 걸릴 수 있고,
과도하면 CPU 성능 낭비가 됩니다 (특히 경량 작업 반복 시).
프로세스 vs 스레드의 컨텍스트 스위칭
| 구분 | 설명 |
|---|---|
| 프로세스 간 전환 | 메모리 맵 전체, 주소 공간 등 전부 변경 → 비용 큼 |
| 스레드 간 전환 | 주소 공간은 공유, 스택/레지스터만 전환 → 비용 작음 |
→ 그래서 경량 작업에는 멀티스레딩이 더 효율적이에요.
컨텍스트 스위칭 요약
| 항목 | 설명 |
|---|---|
| 정의 | 실행 흐름을 다른 프로세스/스레드로 바꾸기 위한 상태 저장 및 복원 |
| 필요 이유 | 멀티태스킹 구현 |
| 저장하는 정보 | PC, 레지스터, 스택, 메모리 맵 등 |
| 발생 시점 | 타임슬라이스 종료, 대기, 우선순위 변화 등 |
| 오버헤드 | 비용 존재, 캐시 무효화 등 성능 저하 가능 |
| 프로세스 vs 스레드 | 프로세스 전환은 무겁고, 스레드는 상대적으로 가볍다 |
🔑 핵심 문장
참고로 다른 이야기이지만 집중력 관점에서 사람의 컨텍스트 스위칭 비용은 매우 크기 때문에 보통 하나의 업무를 끝내고 다음 업무로 넘어가는 것이 좋다.
스레드 수를 많이 만들면 무조건 좋은 거 아니야?
❌ 아니에요.
스레드 수는 많으면 많을수록 좋은 게 아닙니다.
적절하지 않으면 CPU 사용률은 낮고, 컨텍스트 스위칭 비용만 올라갑니다.
컨텍스트 스위칭은 왜 문제가 돼?
스레드가 많아질수록, 운영체제가 CPU를 누구에게 줄지 계속 판단해야 하므로
스레드 간 전환(Context Switching)이 자주 발생하게 됩니다.
따라서 "적정 수의 스레드"를 유지하는 것이 핵심입니다.
그렇다면 스레드 수는 어떻게 정해야 해?
이건 "작업의 성격"에 따라 다릅니다.
크게 두 가지 CPU-bound, I/O-bound로 나눌 수 있어요.
CPU-바운드 작업 (CPU-bound)
CPU가 쉬지 않고 계속 계산해야 하는 작업을 의미합니다.
| 특징 | 설명 |
|---|---|
| 예시 | 암호화, 비디오 인코딩, 시뮬레이션, 수학 계산 등 |
| CPU 점유율 | 매우 높음 |
| 대기 시간 | 거의 없음 (계산 계속함) |
| 적정 스레드 수 | CPU 코어 수 + 1 정도 |
| 이유 | 연산 중인 스레드가 대기 없이 계속 돌기 때문에, 과도하게 늘리면 오히려 컨텍스트 스위칭만 증가 |
이런 작업은 스레드 수를 너무 많이 두면 오히려 성능이 떨어질 수 있어요.
I/O-바운드 작업 (I/O-bound)
CPU보다는 네트워크, DB, 파일 I/O 등의 응답을 기다리는 작업이 많음
| 특징 | 설명 |
|---|---|
| 예시 | DB 쿼리, 파일 입출력, 웹 요청 처리 등 |
| CPU 점유율 | 낮음 (대기 시간 많음) |
| 대기 시간 | 상대적으로 큼 |
| 적정 스레드 수 | CPU 코어 수보다 훨씬 많게 설정 가능 |
| 이유 | 대기 중인 스레드는 CPU를 점유하지 않기 때문에, 스레드 수를 늘려도 성능 저하가 없음. 단, 너무 많으면 컨텍스트 스위칭 증가 가능성은 있음 |
실무 웹 서버는 거의 대부분 이 I/O-바운드에 해당합니다.
💡 예시: 웹 서버
📌 이 경우:
실무 정리 요약
| 항목 | CPU-bound | I/O-bound |
|---|---|---|
| 작업 성격 | 계산 중심, 대기 없음 | 대기 중심, 계산 적음 |
| CPU 점유율 | 높음 | 낮음 |
| 스레드 수 전략 | CPU 코어 수 + 1 | CPU 코어보다 훨씬 많은 수 가능 |
| 주의할 점 | 너무 많으면 컨텍스트 스위칭 비용 증가 | 너무 적으면 자원 낭비, 너무 많으면 비용 증가 가능성 있음 |
작업이 CPU 중심인지(I/O 중심인지) 먼저 구분하고,
그에 맞는 스레드 수를 설정해야 자원을 낭비하지 않고 최대한 활용할 수 있습니다.
📌실무 팁