스레드에서 start()와 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("메인 스레드 실행 중");
}
}
결과:
동작 방식:
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("메인 스레드 실행 중");
}
}
결과:
| 메서드 | 설명 | 실행방식 |
|---|---|---|
| start() | 새로운 스레드를 생성하고, 해당 스레드에서 run()을 실행 | 새로운 스레드에서 병렬로 실행됨 |
| run() | 스레드에서 수행할 작업을 정의하지만, 직접 호출하면 새로운 스레드가 생성되지 않음 | 현재 스레드에서 순차적으로 실행됨 (메인 스레드 등) |
run()을 직접 호출하면, 새로운 스레드를 생성하지 않고 현재 실행 중인 스레드(예: 메인 스레드)에서 그 메서드가 실행됩니다. 이는 일반적인 메서드 호출과 동일합니다. 즉, 동기적으로 실행되며, 다른 작업과 병렬로 수행되지 않습니다.
반면, start()를 호출하면 새로운 스레드가 생성되고, 그 스레드에서 run() 메서드가 실행됩니다. 이 경우 작업이 병렬로 실행되어 멀티스레딩이 가능합니다. start()는 실제로 새로운 스레드를 운영체제가 생성하고 관리할 수 있도록 하며, run() 메서드는 그 스레드 안에서 실행됩니다.
스레드에서 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이 발생합니다.
스레드가 완료되는 시점을 알기 위해서는 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("메인 스레드 완료");
}
}
결과:
join() 메서드를 사용하면 스레드가 끝날 때까지 대기할 수 있으므로, 스레드가 언제 완료되었는지 확인할 수 있습니다.