자바에서 스레드를 구현할 수 있는 방법은 두 가지가 있습니다.
Runnable
Runnable은 인터페이스 입니다.
인터페이스를 이용해서 구현하면 재사용성이 높고 코드의 일관성을 유지할 수 있습니다.
또한, 다른 클래스를 상속 받아서 사용할 수 있습니다.
Runnable 인터페이스는 아래와 같습니다. 추상 메서드 run()를 가지고 있어서 반드시 오버라이딩하여 구현해 주어야 합니다.
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface {@code Runnable} is used
* to create a thread, starting the thread causes the object's
* {@code run} method to be called in that separately executing
* thread.
* <p>
* The general contract of the method {@code run} is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
사용 예시는 아래와 같습니다.
printNum을 재사용하여 스레드를 만들 수 있습니다.
@Test
public void runnable() {
Runnable printNum = new RunnableClass(10);
Thread thread1 = new Thread(printNum);
Thread thread2 = new Thread(printNum);
thread1.start();
thread2.start();
}
static class RunnableClass implements Runnable {
int num;
public RunnableClass(int num) {
this.num = num;
}
@Override
public void run() {
for(int i=0; i<=num; ++i){
System.out.println(i);
}
}
}
Thread
Thread는 클래스 입니다.
사용할 때에는 상속(extends)하여 사용해야 합니다. 그래서 다른 클래스를 상속 받을 수 없습니다.
Thread 클래스는 아래와 같습니다. Runnable 인터페이스를 상속받고 있습니다.
public class Thread implements Runnable {
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives();
static {
registerNatives();
}
/// 중략 ///
/**
* If this thread was constructed using a separate
* {@code Runnable} run object, then that
* {@code Runnable} object's {@code run} method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of {@code Thread} should override this method.
*
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
if (target != null) {
target.run();
}
}
}
사용 예시는 아래와 같습니다.
thread1과 thread2 인스턴스를 각각 만들어서 사용하고 있습니다.
@Test
public void thread() {
ThreadClass thread1 = new ThreadClass(10);
ThreadClass thread2 = new ThreadClass(10);
thread1.start();
thread2.start();
}
static class ThreadClass extends Thread {
int n;
public ThreadClass(int n) {
this.n = n;
}
@Override
public void run(){
for (int i = 0; i < n; i++) {
System.out.println(i);
}
}
}
Runnable과 Thead 사용에 대한 생각
자바에서는 다중상속을 허용하지 않습니다. Runnable 인터페이스를 사용하여 구현하면 다른 클래스를 상속 받을 수 있기 때문에 확장성에서 득을 볼 수 있다고 생각합니다.
스레드 사용할 때 주의사항 : start()과 run() 사용
run()을 호출하는 것은 생성한 스레드 객체를 실행하는 것이 아니라, 단순히 스레드 클래스 내부의 run()을 실행시키는 것 입니다. run()를 사용하면 main()의 메인 스레드가 run() 메소드를 실행하기 때문에 새로운 스레드가 생기지 않아서 병렬 처리를 할 수 없습니다.
반면, start()를 이용하면 새로운 스레드 실행에 필요한 호출 스택(call stack)을 생성하고 run()을 호출합니다. 생성된 호출 스택에 run()을 담습니다 (스택에 올라가면 메서드는 실행됩니다) 따라서 멀티 스레드로 병렬 처리를 할 수 있습니다.
참고
'IT > Java' 카테고리의 다른 글
자바의 비동기 API (0) | 2023.01.15 |
---|---|
프로세스와 스레드 그리고 멀티 태스킹 (0) | 2023.01.10 |
동시성(Concurrency) 과 병렬성(Parallel) (0) | 2023.01.10 |
Optional 클래스 사용 (0) | 2023.01.08 |
Map 처리 (0) | 2022.12.19 |