멀티 쓰레드란?

멀티쓰레드(Multi Thread)는 하나의 프로세스 내에서 둘 이상의 쓰레드가 동시에 작업을 수행하는 것을 의미한다. 비슷한 개념으로 멀티 프로세스(Multi Process)는 여러 개의 CPU를 사용하여 여러 프로세스를 동시에 수행하는 것을 의미한다.
멀티 쓰레드와 멀티 프로세스 모두 여러 흐름을 동시에 수행하다는 공통점을 가지고 있다. 하지만 멀티 프로세스는 각 프로세스가 독립적인 메모리를 가지고 별도로 실행되는 반면, 멀티 쓰레드는 각 쓰레드가 자신이 속한 프로세스의 메모리를 공유한다는 점이 다르다.
멀티 쓰레드는 각 스레드가 자신이 속한 프로세스의 메모리를 공유하므로, 시스템 자원의 낭비가 적다. 하나의 쓰레드가 작업을 할 때 다른 쓰레드가 별도의 작업을 할 수 있어 사용자 경험도 향상될 수 있다.
코딩교육 티씨피스쿨
4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등
tcpschool.com
Runnable 인터페이스 구현 vs Thread 클래스 상속
Java에서 멀티쓰레드를 구현하는 방법으로는 Runnable 인터페이스를 구현하거나 Thread 클래스를 상속하는 방법이 있다.
1. Runnable 인터페이스 구현
class MyRunnable implements Runnable {
private final String threadName;
MyRunnable(String name) {
this.threadName = name;
}
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(threadName + " 실행 중: " + i + "번째 반복");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
System.out.println(threadName + " 인터럽트 발생");
}
}
System.out.println(threadName + " 종료");
}
}
public class Main {
public static void main(String[] args) {
Thread thread1 = new Thread(new MyRunnable("스레드1"));
Thread thread2 = new Thread(new MyRunnable("스레드2"));
thread1.start();
thread2.start();
}
}

2. Thread 클래스 상속
class MyThread extends Thread {
private final String threadName;
MyThread(String name) {
this.threadName = name;
}
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(threadName + " 실행 중: " + i + "번째 반복");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
System.out.println(threadName + " 인터럽트 발생");
}
}
System.out.println(threadName + " 종료");
}
}
public class Main {
public static void main(String[] args) {
MyThread thread1 = new MyThread("스레드1");
MyThread thread2 = new MyThread("스레드2");
thread1.start();
thread2.start();
}
}

실행 결과 두 방식 모두 똑같아 보인다. 그런데 왜 구현 방식에 차이가 있는 걸까? 우선 두 방식의 차이를 표로 정리하자면 다음과 같다.
| 구분 | Thread 상속 방식 | Runnable 구현 방식 |
| 상속 제약 | 있음 (다른 클래스 상속 불가) | 없음 |
| 책임 분리 | 실행 코드와 스레드 관리가 한 클래스에 혼합됨 | 실행 코드와 스레드 관리 분리됨 |
| 재사용성 | 낮음 | 높음 |
| 코드 유연성 | 낮음 | 높음 |
| 람다 표현식 활용 가능 | 불가능 | 가능 |
- 상속 vs 구현
- Thread 상속 방식
- Thread 클래스를 직접 상속받아 새로운 클래스를 만든다.
- 클래스가 이미 다른 클래스를 상속받고 있다면 사용이 불가능하다.
- 즉, 자바는 다중 상속을 지원하지 않아서 다른 클래스를 상속 중일 경우 이 방법을 쓸 수 없다.
- Runnable 구현 방식
- Runnable 인터페이스를 구현하는 클래스를 만든다.
- 이미 다른 클래스를 상속받고 있어도 구현이 가능하므로 유연성이 높다.
- Thread 상속 방식
- 코드 설계와 책임 분리
- Thread 상속 방식: 스레드 실행 로직과 스레드 관리가 한 클래스에 같이 존재하므로 책임이 다소 혼합될 수 있다.
- Runnable 구현 방식 실행할 작업을 정의하는 Runnable 객체와 스레드 실행을 관리하는 Thread 객체가 분리되어 코드를 더욱 명확하고 재사용 가능하게 만든다.
- 재사용성과 확장성
- Thread 상속 방식: 새로운 스레드를 생성할 때마다 Thread 클래스를 상속한 새로운 클래스를 정의해야 하므로 중복 코드가 생길 수 있다.
- Runnable 구현 방식: 동일한 Runnable 객체를 여러 스레드에서 실행하거나, 하나의 작업 내용을 여러 스레드에 배분하기 용이하다.
일반적으로는 Runnable 구현 방식을 권장한다고 한다.
- 클래스 설계의 유연성, 상속 제약 해소, 코드 재사용성에서 유리하기 때문
- Runnable은 함수형 인터페이스이므로 람다 표현식과 함께 쓰이기 쉽다는 장점도 있다고 한다
Thread 상속 방식은 간단한 멀티쓰레드 기능 구현이나 쓰레드 전용 기능을 별도 클래스에 집중시켜 구현할 때 주로 활용된다. 하지만 실무나 확장 가능한 코드에서는 유연성 때문에 대체로 Runnable 구현 방식을 선호한다고 한다.