공부방

자바 스레드(Thread)? 본문

문법

자바 스레드(Thread)?

코딩 화이팅 2025. 3. 24. 13:03

https://hyunleo.tistory.com/303

 

프로세스(Process) vs 스레드(Thread)를 쉽게 알아보기

프로세스?사전적 의미 : 실행 중인 프로그램독립적인 작업 단위(실행 중인 프로그램)운영체제가 관리자신 만의 메모리 공간이 따로 있다.다른 프로세스와 메모리를 공유하지 않는다.(독립적)예

hyunleo.tistory.com

오랫동안 궁금했던 프로세스와 스레드의 차이점을 정리해봤다. 그렇다면 자바 스레드란 무엇일까?

 

자바에서 스레드란?

  • 스레드(Thread)는 프로세스 내에서 실행되는 작업 흐름
  • 자바에서는 스레드를 동시에 여러 개 실행할 수 있다.(멀티스레딩)
  • 하나의 프로그램(프로세스) 안에서 동시에 여러 작업을 수행할 수 있도록 해주는 기능
  • 자바에서 스레드는 독립적인 실행 흐름을 가진다.
  • 여러 개의 스레드를 사용하면 병렬로 작업을 처리할 수 있다.

스레드 없는 코드

public class WithoutThread {
    public static void main(String[] args) {
        System.out.println("작업 1 시작");
        작업();  // 3초 걸리는 작업
        System.out.println("작업 2 시작");
        작업();  // 3초 걸리는 작업
        System.out.println("모든 작업 완료");
    }

    public static void 작업() {
        try {
            Thread.sleep(3000); // 3초 동안 멈춤
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
작업 1 시작
(3초 대기)
작업 2 시작
(3초 대기)
모든 작업 완료

작업이 순차적으로 실행되기 때문에, 전체 6초가 걸린다.

스레드를 사용한다면?

class MyThread extends Thread {
    public void run() {
        System.out.println("스레드 시작!");
        try {
            Thread.sleep(3000); // 3초 대기
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("스레드 종료!");
    }
}

public class WithThread {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start(); // 🟢 새로운 스레드 실행

        System.out.println("메인 작업 실행");
        try {
            Thread.sleep(3000); // 3초 대기
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("메인 작업 종료");
    }
}
메인 작업 실행
스레드 시작!
(3초 대기)
스레드 종료!
메인 작업 종료

스레드를 사용하여 여러 작업을 동시에 실행하며 실행 시간이 절반으로 줄어든다.

JVM과 스레드의 관계

  • 운영체제(OS) : 원래는 운영체제(Windows, macOS, Linux)가 스레드를 관리
  • 자바(JVM) : 자바에서는 운영체제 대신 JVM이 스레드를 관리
    • JVM이 스레드를 몇 개 실행할지 결정
    • 스레드가 어디서 실행될지 (메모리 관리) 결정
    • 스레드가 언제 실행되고 언제 멈출지 결정
  • 즉, 자바에서 스레드를 만들면, 운영체제가 아닌 JVM이 실행 순서를 정하고 관리해주는 것

자바에서는 프로세스가 없고 스레드만 존재한다?

  • 완전히 맞는 말은 아님
  • 자바 프로그램 자체는 프로세스이지만, 내부적으로 실행되는 것은 스레드이다.
    • java MyApp 명령어로 자바 프로그램을 실행하면, 운영체제는 새로운 프로세스를 만든다.
    • 하지만 자바 내부에서는 여러 개의 스레드가 실행되면서 작업을 수행한다.
  • 운영체제 관점에서는 자바 프로그램이 하나의 프로세스이다.
  • 하지만 JVM 내부에서는 여러 개의 스레드가 실행되는 구조이다.

JVM이 스레드를 어떻게 관리?

  • JVM이 어떤 스레드를 먼저 실행할지, 언제 실행할지  결정한다는 뜻
  • JVM은 운영체제(OS)의 스레드 스케줄링 방식을 사용해서, 각 스레드의 실행 순서를 자동으로 조절
    • 우선순위 기반(Priority-based) 스케줄링
      • 높은 우선순위를 가진 스레드가 먼저 실행된다.
      • thread.setPriority(Thread.MAX_PRIORITY); 같은 방법으로 설정 가능
    • 시간 분할(time-sharing) 스케줄링
      • 모든 스레드가 순서대로 짧은 시간 동안 실행된다.
      • 특정 스레드가 오래 실행되지 않도록 제한
  • 즉, JVM은 운영체제의 스케줄링 방식을 따라 스레드를 실행 순서를 정한다.

개발자는 단순히 스레드를 생성하고 JVM에 맡긴다.

JVM이 스레드를 직접 관리하기 때문에, 개발자는 직접 컨트롤할 필요가 없다.

class MyThread extends Thread {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " 실행 중!");
        }
    }
}

public class ThreadExample {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();
        MyThread thread3 = new MyThread();

        thread1.start();
        thread2.start();
        thread3.start();

        System.out.println("메인 스레드 종료!");
    }
}
Thread-0 실행 중!
Thread-0 실행 중!
Thread-0 실행 중!
Thread-0 실행 중!
Thread-0 실행 중!
Thread-2 실행 중!
Thread-2 실행 중!
Thread-2 실행 중!
Thread-2 실행 중!
Thread-2 실행 중!
Thread-1 실행 중!
Thread-1 실행 중!
Thread-1 실행 중!
Thread-1 실행 중!
Thread-1 실행 중!
메인 스레드 종료!
메인 스레드 종료!
Thread-1 실행 중!
Thread-2 실행 중!
Thread-2 실행 중!
Thread-2 실행 중!
Thread-1 실행 중!
Thread-1 실행 중!
Thread-1 실행 중!
Thread-1 실행 중!
Thread-0 실행 중!
Thread-0 실행 중!
Thread-0 실행 중!
Thread-0 실행 중!
Thread-0 실행 중!
Thread-2 실행 중!
Thread-2 실행 중!

실제로 필자가 실행해본 결과 thread1, thread2, thread3가 동시에 실행되지만 실행 순서는 JVM이 자동으로 결정

  1. new Thread()를 사용해 스레드 객체를 생성
  2. .start()를 호출해서 스레드를 실행
  3. 나머지는 JVM이 알아서 처리(스레드 실행 순서, 실행 시간 등)

더 자세한 자바 스레드의 작동 과정

위의 코드를 예로 더 자세하게 들어가보자

class MyThread extends Thread {
    public void run() {
        System.out.println("스레드 시작!");
        try {
            Thread.sleep(3000); // 3초 대기
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("스레드 종료!");
    }
}

public class WithThread {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start(); // 🟢 새로운 스레드 실행

        System.out.println("메인 작업 실행");
        try {
            Thread.sleep(3000); // 3초 대기
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("메인 작업 종료");
    }
}
  • 코드 분석
    • 이 코드에서 2개의 스레드(메인 스레드 + 추가 스레드)가 실행된다.
      • main 메서드 : 자바 프로그램이 실행될 때 가장 먼저 실행되는 "메인 스레드"
      • MyThread 클래스 : Thread 클래스를 상속받아서 새로운 스레드를 만드는 역할

  • main 메서드 실행(메인 스레드)
public class WithThread {
    public static void main(String[] args) {
  • 자바 프로그램이 실행되면서 JVM이 main 메서드를 실행
  • 즉, "메인 스레드"가 실행된다.

  • 새로운 스레드 생성
MyThread thread = new MyThread();
  • MyThread 객체를 생성한다. (아직 실행된 것은 아님)
  • 이 단계에서는 단순히 새로운 스레드 객체를 만든 것뿐이다.

  • 새로운 스레드 실행(start 호출)
thread.start();
  • 새로운 스레드 실행!
  • start()를 호출하면 내부적으로 run() 메서드가 실행된다.
  • 하지만 바로 실행되지 않을 수도 있다 -> JVM이 스케줄링을 관리하기 때문에
  • 여기서 중요한 점은 start()는 비동기적으로 실행된다는 것
    • 즉, 메인 스레드는 계속 진행하고, 새로운 스레드는 JVM이 알아서 실행 시점을 정한다.

  • 메인 스레드의 다음 코드 실행
System.out.println("메인 작업 실행");
  • 새로운 스레드를 실행했지만, 메인 스레드는 기다리지 않고 바로 다음 코드로 진행한다..
  • 즉, "메인 작업 실행"이 먼저 출력된다.
    출력 결과 : 메인 작업 실행

  • 메인 스레드가 3초 대기(sleep 호출)
try {
    Thread.sleep(3000); // 3초 대기
} catch (InterruptedException e) {
    e.printStackTrace();
}
  • Thread.sleep(3000) -> 메인 스레드는 3초 동안 멈춤 (대기)
  • 하지만 이 동안에도 새로운 스레드는 실행될 수 있음
    (JVM이 새로운 스레드를 언제 실행할지 결정한다.)

  • 새로운 스레드의 run() 메서드 실행
public void run() {
    System.out.println("스레드 시작!");
  • 새로운 스레드가 실행되면서 "스레드 시작!"이 출력된다.
    출력 결과 : 스레드 시작!

  • 새로운 스레드도 3초 대기 (sleep 호출)
try {
    Thread.sleep(3000); // 3초 대기
} catch (InterruptedException e) {
    e.printStackTrace();
}
  • 새로운 스레드도 3초 동안 멈춤(대기 상태)
  • 이때 메인 스레드는 별개로 실행되고 있다.
    (즉, 메인 스레드와 새로운 스레드는 독립적으로 실행된다.)

  • 메인 스레드의 대기 시간이 끝나면 실행 계속
System.out.println("메인 작업 종료");
  • 메인 스레드는 3초 대기 후 다시 실행된다.
    출력 결과 : 메인 작업 종료

  • 새로운 스레드의 대기 시간이 끝나면 실행 계속
System.out.println("스레드 종료!");
  • 새로운 스레드도 3초 대기 후 실행 계속된다.
    출력 결과 : 스레드 종료!

실행 순서 정리

  1. 메인 스레드 실행 -> 메인 작업 실행 출력
  2. 새로운 스레드 실행 -> 스레드 시작! 출력
  3. 메인 스레드 3초 대기
  4. 새로운 스레드 3초 대기
  5. 메인 스레드 3초 후 실행 재개 -> 메인 작업 종료 출력
  6. 새로운 스레드 3초 후 실행 재개 -> 스레드 종료! 출력

실행 결과가 이렇게 나오는 이유

  1. start()를 호출하면 새로운 스레드가 실행되지만, 메인 스레드는 기다리지 않는다.
  2. Thread.sleep(3000)을 만나면, 해당 스레드는 3초 동안 멈추지만 다른 스레드는 실행 가능
  3. 메인 스레드와 새로운 스레드는 서로 독립적으로 실행된다.
  4. JVM이 스레드 실행 순서를 조절해서 실행 타이밍이 겹치거나 순서가 바뀔 수도 있다.

실행 순서가 항상 동일할까?

  • JVM이 스케줄링을 관리하기 때문에 실행 순서가 달라질 수도 있다.
  • 즉, "스레드 시작!"이 "메인 작업 실행"보다 먼저 나올 수도 있고,
    "메인 작업 종료"가 "스레드 종료!"보다 늦게 나올 수도 있다.
  • JVM이 각 스레드가 언제 실행될지를 자동으로 조절하기 때문이다.
  • 필자가 직접 동작했을 때 실제로 밑처럼 나온다.
메인 작업 실행
스레드 시작!
(3초 대기)
메인 작업 종료
스레드 종료!
메인 작업 실행
스레드 시작!
(3초 대기)
스레드 종료!
메인 작업 종료

실행 흐름 시각화

시간(초) 메인 스레드 새로운 스레드
0 메인 작업 실행 출력 스레드 시작! 출력
0 ~ 3초 3초 대기( sleep(3000) ) 3초 대기( sleep(3000) )
3 메인 작업 종료 출력 -
3 - 스레드 종료! 출력

한 줄 요약

  • 메인 스레드와 새로운 스레드는 독립적으로 실행된다.
  • Thread.sleep()을 만나면 해당 스레드는 대기하지만, 다른 스레드는 실행될 수 있다.
  • JVM이 스레드 실행 순서를 결정하기 때문에 실행 순서는 항상 같지 않을 수도 있다.

'문법' 카테고리의 다른 글

쿠키 vs 세션 vs 토큰  (0) 2025.03.27
Java의 예외 처리  (0) 2025.03.24
JVM(Java Virtual Machine)  (1) 2025.03.24
프로세스(Process) vs 스레드(Thread)를 쉽게 알아보기  (0) 2025.03.20