[Java] 스레드 구동 방식

나른한 개발자·2025년 12월 31일

f-lab

목록 보기
8/44

자바 스레드는 OS 스레드와 1:1로 매핑되며 OS 스케쥴러에 의해 스케쥴링 된다. 즉 자바 스레드 1개가 생성되면 os의 스레드도 한개 생성된다.

1. 생성과 등록

new Thread()를 하면 스레드 객체가 생성되고 start()를 다음과 같은 동작이 실행된다.

  • 스레드 생성 요청: JVM이 OS 스레드 생성을 요청한다.
  • TCB(Thread Control Block): OS는 스레드를 관리하기 위한 TCB를 생성한다. 이곳에는 스레드 ID, 우선순위, 레지스터 값을 저장할 공간이 있다.
  • 스택 할당: OS는 스레드 전용 메모리 공간인 stack을 할당한다.
  • 준비 큐 진입: 스레드는 준비 큐에 진입하여 작업을 기다린다.

2. 스케쥴링과 실행

CPU 코어는 한정되어 있고 스레드는 많기 때문에, OS의 스케줄러(Scheduler)가 누구를 실행시킬지 결정한다.

  • 디스패치: 스케쥴러가 대기중인 스레드를 cpu 코어에 올린다.
  • 레지스터 로딩: 선택한 스레드의 TCB에 저장된 Program counter(다음 실행할 코드위치)와 스택 포인터 값(현재 스레드가 사용중인 스택의 가장 top주소)을 CPU 레지스터에 복사한다.
  • 실행: cpu는 코드 영역을 불러와 연산을 수행하고 결과나 지역변수는 stack에 저장한다.

3. 컨텍스트 스위칭

스레드가 구동되는 핵심은 "줬다 뺏기"이다. 한 스레드가 코어를 독점하지 못하도록 OS는 아주 짧은 시간(Time Quantum)만 허락한다.

  • 타이머 인터럽트: 정해진 시간이 되면 os가 cpu에 신호를 보낸다.
  • 현 상태 저장: cpu는 작업중인 레지스터 값들을 현 스레드의 TCB에 저장한다.
  • 다음 스레드 로드: 다음 순서인 스레드의 TCB에서 이전 정보를 꺼내 CPU 레지스터에 덮어씌운다.
  • 작업 재개: 새로운 스레드는 중단된적이 없는 듯이 작업을 이어간다.

TCB(장부) 작성 → 스택 할당 → CPU 레지스터에 값 로딩 → 실행 → 시간 다 되면 레지스터 값 저장 후 교체"의 무한 반복이다.

병렬성과 동시성

병렬성(Parallelism)

병렬성은 직관적으로 명령어를 메모리에서 뽑아 해석하고 실행하는 반도체 유닛인 여러개의 코어에 맞춰 여러개의 프로세스, 스레드를 돌려 병렬로 작업들을 동시 수행하는 것을 말한다. 

듀얼코어, 쿼드코어, 옥타코어 등등 이런 명칭이 붙는 멀티코어 프로세서가 달린 컴퓨터에서 할 수 있는 방식이다.

동시성(concurrency)

동시성은 둘 이상의 작업이 동시에 실행되는 것을 의미한다. 이 '동시' 라는 의미에서 병렬성과 동시성의 한글 의미가 헷갈릴수 있다. Parallelism가 물리적으로 정말로 동시에 실행하는 것이라고 하면, Concurrency는 동시에 실행하는 것처럼 보이게 하는 것으로 이해하면 된다.

여러 작업을 동시에 처리하는 것처럼 보이게 만들어, 사용자에게 더 빠른 반응성을 제공하기 위해서다. 그리고 이렇게 진행 중인 작업들을 A → B → C → D 로 번갈아 바꾸는 것을 Context Switching 이라고 부른다.

코어 개수보다 실행해야하는 스레드가 많을때 사용합니다.

타이머 인터럽트가 필요한 이유

타이머 인터럽트가 없다면 독점 문제가 생길 수 있다. 한 스레드가 무한 루프에 빠지거나 아주 긴 계산을 시작하면, 그 스레드가 끝날 때까지 CPU 코어를 절대 놓아주지 않을 것이다. 그렇게 되면 마우스 클릭도 안 먹히고, 다른 프로그램들이 모두 멈춰버리는 '프리징(Freezing)' 현상이 발생한다.

그래서 OS는 타이머 인터럽트라는 장치를 사용한다. 하드웨어 타이머가 일정 시간(Time Slice)마다 CPU에 "자, 시간 다 됐어! 다음 사람한테 넘겨!"라는 전기 신호를 강제로 보낸다.

이 신호를 받은 CPU는 하던 일을 멈추고 제어권을 OS에게 넘긴다. 이 때문에 모든 스레드가 조금씩이라도 CPU를 나누어 쓸 수 있게 되는 것이다.

스레드는 동시성?병렬성?

스레드 구동 방식은 동시성과 병렬성 둘 중 한 방식으로 일어날 수 있다. 보통은 병렬성과 동시성이 혼합되어 일어난다.

코어가 1개인 경우

  • 만약 코어가 딱 1개라면, 물리적으로 두 일을 같은 시간에 할 수 없어 무조건 동시성으로 동작한다.
  • 타이머 인터럽트를 이용해 A와 B를 번갈아 가며 실행한다.
  • 진짜 동시는 아니지만, 동시에 하는 것처럼 보임.

코어가 여러개일 때: 병렬 + 동시

요즘 스마트폰이나 PC는 보통 4코어, 8코어 이상이다. 즉 병렬성과 동시성이 함께 일어난다.

1. 병렬성이 일어나는 경우

  • 스레드 A는 1번 코어에서, 스레드 B는 2번 코어에서 동시에 돌아간다.
  • 이때는 타이머 인터럽트가 서로를 방해할 필요가 없다. 각자 자기 코어에서 실행하면 된다.
  • 진짜 동시에 실행된다.

2. 동시성 (Concurrency)이 섞이는 경우

그런데 우리는 보통 스레드를 8개만 쓰지 않는다. 크롬 브라우저, 카카오톡, 자바 프로그램, 백신 등 수백 개의 스레드가 떠 있다.

코어는 8개인데 스레드가 500개라면?

8개의 코어가 각각 수십 개의 스레드를 맡아서 번갈아 가며(동시성) 처리한다. 결과적으로 전체 시스템 관점에서는 병렬(8개 코어가 동시에 일함)이면서, 각 코어 내부에서는 동시성(번갈아 가며 일함)이 일어나는 구조이다.

스레드가 중요한 이유

  • 응답성 향상: 파일 다운로드나 데이터 처리와 같은 시간이 오래 걸리는 작업을 별도의 스레드에서 실행하면 메인 스레드가 사용자 입력을 계속 받을 수 있어 사용자 입장에서 프로그램이 멈춘 것 처럼 보이지 않는다. (스레드가 하나라면 그 작업이 끝날때까지 멈춘것 처럼 보일 수 있음)
  • 자원 효율성: 스레드는 같은 프로세스 내에서 메모리 공간을 공유하므로 메모리 사용량이 적고, 생성/삭제/전환 비용이 프로세스보다 훨씬 적다.
  • 동시성 처리: 웹 서버처럼 여러 클라이언트 요청을 한꺼번에 처리해야하는 경우, 각 요청을 별도 스레드에서 처리하면 효율적이고, 처리량이 증가한다.

Inpa Dev 👨‍💻:티스토리

profile
Start fast to fail fast

0개의 댓글