코드스쿼드에서 수업을 듣던 중 다음과 같은 질문이 나왔습니다.
이 코드에서
run
으로 실행시킨 것과start
로 실행시킨 것의 차이를 아나요?
어떤 차이가 있는지 정확히 몰라 이번 기회에 작성해보려 합니다.
먼저 스레드
는 프로세스 내의 작업의 실행주체입니다. 두 개 이상의 스레드를 가진 프로그램을 멀티스레드 프로그램이라 합니다.
Java에서는 일반 스레드(Normal Thread)
와 데몬 스레드(Daemon Thread)
가 존재합니다. JVM에서 생성되는 모든 스레드에서 메인 스레드를 제외한 나머지 스레드가 데몬 스레드입니다.
데몬 스레드는 일반 스레드를 돕는 보조적 역할을 담당하는 스레드입니다. 그렇기 때문에 일반 스레드에 종속적이며 일반 스레드가 종료되면 데몬 스레드는 강제 종료되는 특징을 가지고 있습니다.
자바에서 스레드를 생성하는 방법은 다음과 같은 두 가지 방법이 있습니다.
1. Thread
클래스를 상속
class Task extends Thread {
@Override
public void run() {
System.out.println("스레드의 작업 내용입니다.");
}
}
}
Thread
클래스를 상속 받은 후 run
메서드를 오버라이딩하여 스레드의 작업 내용을 정의합니다.
Runnable
인터페이스를 구현class Task implements Runnable {
@Override
public void run() {
System.out.println("스레드의 작업 내용입니다.");
}
}
}
Runnable
인터페이스를 구현한 후 마찬가지로 run
메서드를 오버라이딩 합니다.
이중 Runnable
인터페이스를 구현하는 방법으로 스레드를 생성해 run과 start의 차이를 알아보도록 하겠습니다.
아래는 스레드의 작업내용입니다. 단순히 자신의 이름을 출력하고 1초를 쉬는 과정을 3번 반복하는 내용입니다.
private static Consumer<String> task = (threadName) -> {
for (int i = 0; i < 3; i++) {
System.out.println("[" + threadName + "] START!" + " " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
먼저 run
메서드를 통해 스레드의 작업을 수행해보겠습니다.
public static void main(String[] args) {
Thread t1 = new Thread(() -> task.accept("thread1"));
Thread t2 = new Thread(() -> task.accept("thread2"));
Thread t3 = new Thread(() -> task.accept("thread3"));
t1.run();
t2.run();
t3.run();
}
run
을 통해 스레드를 실행시키면 스레드가 순서대로 실행되는 것을 확인할 수 있습니다. 또한 모두 main 스레드에 의해 실행되는 것을 확인할 수 있습니다.
이번에는 start
메서드를 통해 스레드의 작업을 수행해 보겠습니다.
public static void main(String[] args) {
Thread t1 = new Thread(() -> task.accept("thread1"));
Thread t2 = new Thread(() -> task.accept("thread2"));
Thread t3 = new Thread(() -> task.accept("thread3"));
t1.start();
t2.start();
t3.start();
}
start
메서드를 통해 스레드를 실행시키면 스레드의 실행이 일관되지 않고 무작위로 실행되는 것을 확인할 수 있습니다.
위의 결과만으로는 알 수 없는 내용이 하나 더 있습니다. 스레드의 작업이 수행될 때 run
방식은 스레드 하나씩 실행되고 start
방식은 스레드 1, 2, 3이 동시에 실행된다는 차이가 있었습니다.
왜 이런 결과가 나오는 걸까요?
run
방식은 단순히 오버라이딩한 run() 메서드를 호출하는 것이고, start
는 새로운 스레드를 생성하고 필요한 call stack을 생성한 후 run()을 호출하기 때문입니다.
https://medium.com/@lunay0ung/thread-daemon-thread-3b89ce606b04
https://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html