동시성 문제에 대해 공부하던 중 Runnable Interface와 Thread에 정리할 필요가 있었다.
쓰레드란 프로그램 실행의 가장 작은 단위로 자바 애플리케이션을 만들어 사용하면 1개의 main 쓰레드에 의해 프로그램이 실행된다. 여러 쓰레드를 사용하기 위해서는 따로 쓰레드를 만들어 실행 시켜주어야 한다.
쓰레드를 구현하는 방법은 Thread 클래스를 상속받아 구현하거나 Runnable 인터페이스를 implements 하여 구현하는 2가지 방법이 있다.
Thread 클래스를 이용한다면 Thread 클래스를 상속받아 내부에서 run 메소드를 구현한다. 그후 Thread의 start 메소드를 호출하면 run 메소드가 실행된다.
static class ThreadExample extends Thread {
@Override
public void run() {
System.out.println("run Thread);
}
}
@Test
void ThreadTest() {
Thread thread = new ThreadExample();
thread.start();
}
run 메소드를 직접 호출하는 것이 아닌 start를 호출하여 run메소드를 호출하는 이유는 직접 run을 호출하는 것은 메인 쓰레드에서 객체의 메소들르 호출하는 것에 불과하기 때문에 별도의 쓰레드로 실행시키려면 JVM의 도움이 필요하다. start 메소드를 살펴보자
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
start 메소드는 다음과 같은 과정으로 진행된다.
따라서 Thread는 클래스를 상속받게 되면 다른 클래스를 상속받을 수 없다. 그래서 Runnable 인터페이스를 구현하여 쓰는 경우가 많다.
Runnable 인터페이스는 함수형 인터페이스로 람다로도 사용이 가능하다.
Runnable ex2 = new Runnable(){
@Override
public void run(){
System.out.println("Runnable Example");
}
};
Runnable ex = () -> System.out.println("Runnable example"); //람다 사용
Thread thread = new Thread(ex);
thread.start();
Runnable과 Thread 모두 쓰레드 구현이 가능하지만 여러 측면으로 Runnable을 쓰는 것이 좋다. Runnable은 람다도 사용가능하고 상속할 필요도 없으며 자우너 사용량도 Thread보다 적다. 그러나 Thread 관련 기능의 확장이 필요한 경우에는 Thread 클래스를 상속받아 구현해야 하는 경우도 있다. 그러나 대부분 Runnable 인터페이스를 사용하면 해결이 가능하다.