Thread : start()와 run()

서버란·2024년 9월 19일

자바 궁금증

목록 보기
22/35

스레드에서 start()와 run() 메서드는 매우 중요한 차이가 있습니다. 둘 다 스레드를 실행하는 데 관련이 있지만, 그 목적과 동작 방식은 다릅니다.

1. start() 메서드

  • start() 메서드는 새로운 스레드를 생성하고, 그 스레드 안에서 run() 메서드를 실행하는 역할을 합니다.
  • 자바에서 Thread 클래스 또는 Runnable 인터페이스를 구현한 객체에서 start()를 호출하면, JVM이 새로운 스레드를 만들고, 해당 스레드가 run() 메서드를 호출하여 병렬로 실행됩니다.
  • 이 메서드를 호출하지 않고 run()만 호출하면, 새로운 스레드가 생성되지 않고 메인 스레드에서 코드가 실행됩니다.

동작 방식:
1. start()를 호출하면 JVM이 새로운 스레드를 생성합니다.
2. 생성된 새로운 스레드에서 run() 메서드가 자동으로 호출됩니다.
3. start() 메서드를 통해 시작된 스레드는 비동기적으로 실행됩니다.

예시:

class MyThread extends Thread {
    public void run() {
        System.out.println("스레드 실행 중");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();  // 새로운 스레드에서 run() 실행
        System.out.println("메인 스레드 실행 중");
    }
}

결과:

  • start()를 호출하면 MyThread의 run() 메서드는 새로운 스레드에서 병렬로 실행되기 때문에 메인 스레드 실행 중과 스레드 실행 중 메시지가 비동기적으로 출력될 수 있습니다.

2. run() 메서드

  • run() 메서드는 실제로 스레드가 수행할 작업을 정의하는 메서드입니다. 하지만 run()을 직접 호출하는 것은 새로운 스레드를 생성하지 않고, 현재 실행 중인 스레드에서 메서드를 호출하는 것과 같습니다.
  • 즉, run()을 직접 호출하면 일반적인 메서드 호출처럼 작동하며, 새로운 스레드에서 병렬로 실행되지 않습니다.

동작 방식:
1. run() 메서드를 직접 호출하면 그 메서드는 새로운 스레드에서 실행되지 않고 현재 스레드(예: 메인 스레드)에서 실행됩니다.
2. run() 메서드는 Thread 또는 Runnable 구현 클래스에서 오버라이드되어 작업 내용을 정의하는 데 사용됩니다.

예시:

class MyThread extends Thread {
    public void run() {
        System.out.println("스레드 실행 중");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.run();  // 새로운 스레드가 아닌 메인 스레드에서 실행
        System.out.println("메인 스레드 실행 중");
    }
}

결과:

  • run() 메서드를 직접 호출하면 이 코드는 새로운 스레드에서 실행되지 않고 메인 스레드에서 실행되므로, 스레드 실행 중 메시지가 먼저 출력된 후 메인 스레드 실행 중이 출력됩니다. 이 방식은 새로운 스레드를 생성하지 않기 때문에 멀티스레딩이 아닙니다.

차이점 요약

메서드설명실행방식
start()새로운 스레드를 생성하고, 해당 스레드에서 run()을 실행새로운 스레드에서 병렬로 실행됨
run()스레드에서 수행할 작업을 정의하지만, 직접 호출하면 새로운 스레드가 생성되지 않음현재 스레드에서 순차적으로 실행됨 (메인 스레드 등)

왜 start()를 사용해야 하는가?

  • 병렬 실행: start()를 호출하면 새로운 스레드가 생성되어 run() 메서드를 병렬로 실행할 수 있습니다. 이를 통해 여러 작업을 동시에 수행할 수 있습니다.
  • 멀티태스킹: start()를 사용하면 운영체제가 여러 스레드를 관리하고, 각 스레드를 독립적으로 실행할 수 있게 됩니다. 이로 인해 멀티태스킹과 비동기 처리가 가능합니다.
  • run() 메서드의 역할: run() 메서드는 스레드가 실행할 코드를 정의하는 곳이며, 이를 직접 호출하면 단순한 메서드 호출에 불과하므로 멀티스레딩의 목적을 달성할 수 없습니다.

Q1. run()을 직접 호출했을 때와 start()로 호출했을 때의 실행 결과는 왜 다른가요?

run()을 직접 호출하면, 새로운 스레드를 생성하지 않고 현재 실행 중인 스레드(예: 메인 스레드)에서 그 메서드가 실행됩니다. 이는 일반적인 메서드 호출과 동일합니다. 즉, 동기적으로 실행되며, 다른 작업과 병렬로 수행되지 않습니다.

반면, start()를 호출하면 새로운 스레드가 생성되고, 그 스레드에서 run() 메서드가 실행됩니다. 이 경우 작업이 병렬로 실행되어 멀티스레딩이 가능합니다. start()는 실제로 새로운 스레드를 운영체제가 생성하고 관리할 수 있도록 하며, run() 메서드는 그 스레드 안에서 실행됩니다.

Q2. 스레드에서 start() 메서드를 두 번 호출하면 어떻게 되나요?

스레드에서 start() 메서드를 두 번 호출하면 IllegalThreadStateException 예외가 발생합니다. 이유는, 자바에서 하나의 Thread 객체는 한 번만 실행될 수 있기 때문입니다.

스레드를 한 번 시작하고 나면, 다시 start()를 호출하여 같은 스레드를 재시작할 수 없습니다. 만약 동일한 Thread 객체를 다시 실행하려면, 새로운 Thread 객체를 만들어야 합니다.

예시:

class MyThread extends Thread {
    public void run() {
        System.out.println("스레드 실행 중");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();  // 스레드 시작
        thread.start();  // 예외 발생
    }
}

이 코드를 실행하면 IllegalThreadStateException이 발생합니다.

Q3. start()로 스레드를 실행했을 때, 스레드가 언제 완료되는지 알 수 있는 방법은 무엇인가요?

스레드가 완료되는 시점을 알기 위해서는 Thread.join() 메서드를 사용할 수 있습니다. join() 메서드는 해당 스레드가 완료될 때까지 호출한 스레드가 기다리도록 만듭니다.

즉, join() 메서드를 호출하면 스레드가 완료될 때까지 메인 스레드가 대기하고, 해당 스레드가 종료된 후에야 메인 스레드가 이어서 실행됩니다.

예시:

class MyThread extends Thread {
    public void run() {
        System.out.println("스레드 실행 중");
        try {
            Thread.sleep(2000);  // 스레드가 2초 동안 실행
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("스레드 완료");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();  // 스레드 시작
        
        try {
            thread.join();  // 메인 스레드는 thread가 끝날 때까지 기다림
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("메인 스레드 완료");
    }
}

결과:

  1. "스레드 실행 중" 출력
  2. 스레드가 2초 후에 "스레드 완료" 출력
  3. 스레드가 완료된 후 "메인 스레드 완료"가 출력됩니다.

join() 메서드를 사용하면 스레드가 끝날 때까지 대기할 수 있으므로, 스레드가 언제 완료되었는지 확인할 수 있습니다.

profile
백엔드에서 서버엔지니어가 된 사람

0개의 댓글