개발 학습 실습실

이 사이트의 실습은 자바스크립트를 켜야 움직입니다. 아래는 같은 내용을 글로 적은 것입니다.

공부 › Java › 스레드와 동시성

프로세스와 스레드

일꾼을 늘리는 두 가지 방법

프로그램을 실행하면 프로세스가 하나 생기고, 그 안에서 실제로 코드를 실행하는 것이 스레드입니다. 0.3초씩 걸리는 작업 세 개를 스레드 하나로, 한 프로세스 안의 스레드 세 개로, 프로세스 세 개로 나눠 실행해 봅니다. 메모리를 함께 쓰는지와, 하나가 죽었을 때 나머지가 어떻게 되는지가 다릅니다.

실행으로 대조 · JDK 21에서 아홉 가지 조합을 실행해 확인

이 실습에 나오는 개념

프로세스와 스레드
프로세스는 실행 중인 프로그램으로, 운영체제로부터 독립된 메모리 공간을 할당받는다. 스레드는 프로세스 안에서 실제로 작업을 수행하는 실행 흐름으로, 같은 프로세스의 스레드들은 메모리(힙, 코드, 데이터)를 공유하고 스택만 따로 가진다. 그래서 스레드 간에는 데이터를 주고받기 쉽지만 동시에 같은 데이터를 건드리는 문제가 생긴다.
IPC(프로세스 간 통신)
서로 독립된 메모리를 가진 프로세스들이 데이터를 주고받는 방법이다. 파이프, 메시지 큐, 공유 메모리, 소켓 등이 있다. 서버 프로그램 사이의 통신은 대부분 소켓 위에서 동작하는 HTTP나 메시지 브로커를 이용한다.
런타임 데이터 영역
JVM이 프로그램을 실행하면서 사용하는 메모리 영역이다. 스레드마다 따로 갖는 영역으로 PC 레지스터, JVM 스택, 네이티브 메서드 스택이 있고, 모든 스레드가 공유하는 영역으로 힙과 메서드 영역이 있다. 어떤 데이터가 스레드 간에 공유되는지를 이해하는 기준이 된다.
컨텍스트 스위칭
CPU가 실행하던 스레드(또는 프로세스)를 멈추고 다른 것으로 바꿔 실행하는 과정이다. 하던 작업의 상태를 저장하고 다음 작업의 상태를 불러와야 하며, 이 전환 자체에 시간이 든다. 스레드가 CPU 코어 수보다 지나치게 많으면 실제 작업보다 전환에 드는 시간이 늘어난다.

이렇게 바꿔 보세요

처음 설정으로 실행하면

  1. 프로그램을 실행해 프로세스 1개를 만듭니다. 운영체제가 이 프로세스에 메모리를 내주고, counter 변수는 그 안에 하나 있습니다. 그 안에서 스레드 3개를 만듭니다. 스레드는 실행 흐름(스택)만 각자 가지고, 프로세스의 메모리는 함께 씁니다.
  2. 스레드 3개가 각자 작업을 하나씩 맡아 동시에 시작합니다. 서로 기다리지 않습니다.
  3. 남은 스레드들이 작업을 끝내고 같은 counter를 올립니다. counter는 3입니다. 변수 하나를 여럿이 함께 쓰는 것이므로, 동시에 건드릴 때의 문제는 따로 막아야 합니다(다음 개념인 경쟁 상태).

실행 결과

코드

static int counter = 0;                 // 프로세스의 메모리에 있는 변수

static void work(int id) {
    try { Thread.sleep(300); } catch (InterruptedException e) { return; }   // 0.3초 걸리는 작업
    counter++;
}

// 같은 프로세스 안에 스레드 3개
for (int i = 1; i <= 3; i++) {
    int id = i;
    new Thread(() -> work(id)).start();
}

이 모형의 전제

아홉 가지 조합을 이 PC의 JDK 21에서 실제로 실행해 확인했습니다. 스레드 3개는 0.3초, 스레드 1개는 0.9초가 걸렸고, 스레드들은 같은 counter를 3까지 올린 반면 프로세스 3개는 각자 1이었습니다. 예외는 해당 스레드만 끝냈고, System.exit는 같은 프로세스의 모든 스레드를 끝냈으며, 프로세스가 따로일 때는 죽은 프로세스 외에는 정상 종료했습니다. 프로세스를 만드는 데 드는 시간과 메모리는 화면에 넣지 않았습니다(실제로는 JVM을 새로 띄우는 만큼 훨씬 큽니다).

앞 실습: 병렬 스트림과 공용 풀 · 다음 실습: 스레드의 생성과 상태

이 실습에 나오는 개념

이 실습에서 보는 것

설정

코드


      
    

그림

실행 비교

이렇게 바꿔 보세요