쓰레드(Thread)

- 디스크에 존재하는 프로그램이 실행되면 OS로부터 메모리를 할당받아 프로세스 상태가 됨
- 실제로 작업이 수행되기 위해서는 CPU를 점유해야하는데, 이때 작업 단위를 쓰레드라고 함
- 하나의 프로세스는 하나 이상의 쓰레드를 가짐
Multi-threading
- 하나의 프로그램에서 동시에 여러 작업이 일어날 수 있음
- 이는 쓰레드가 동시에 실행되는 것이 아니라 쓰레드 간에 switch가 발생하는 것임
- OS의 스케줄러가 CPU를 골고루 점유하도록 쓰레드를 배분하는 역할을 함
- 쓰레드는 각각 자신만의 작업공간(context)를 가짐 (자원이 각각 저장됨)
- 여러 쓰레드가 CPU를 번갈아 점유하게 되면서 context switch가 발생함
멀티 쓰레드에서 발생할 수 있는 문제 상황
- 각 쓰레드 사이에는 공유하는 자원(resource ; 변수, 메모리 등)이 있을 수 있음 (자바에서는 static instance)
- 공유 자원(static resource)를 각 쓰레드가 차지했을 때 문제가 발생할 수 있음
- 여러 쓰레드가 자원을 공유하여 작업 시 서로 자원을 차지하려는 자원 경쟁(race condition)이 발생할 수 있음
- race condition이 발생하면 각 쓰레드에서 공유 자원을 변경하게 되고 쓰레드마다 다른 값을 가지게 될 수 있음
- 여러 쓰레드가 공유하는 자원 중 race condition이 발생할 수 있는 부분을 임계 영역(critical section)이라고 함
- 이를 방지하기 위해 critical section에 lock을 걸어 동기화(synchronization)를 구현해야함
- 한 쓰레드가 공유 자원을 사용하고 있으면 다른 쓰레드는 사용할 수 없게끔 해줌 (순차적으로 사용)
- 자바에서는 synchronized method, synchronized block으로 동기화를 구현함
※ 참고 ※
- 웹 프로그래밍에서는 웹서버 자체에 멀티쓰레드가 구현되어 있어서 따로 멀티쓰레드를 구현할 일이 없음
- 안드로이드 프로그래밍 등에서 쓰레드를 직접 생성하고 쓰레드 간 메세지를 주고 받아야 할 일이 발생할 수 있음
자바에서 쓰레드 만들기
- Thread 클래스를 상속받음
- 이미 다른 클래스를 상속받은 경우(자바는 단일 상속만 지원하므로 Thread 상속받지 못함) Runnable 인터페이스와run() 메서드를 구현
Thread 클래스를 상속받을 때
- 쓰레드가 될 클래스가 Thread 클래스를 상속받음
- Thread의 메서드 start()를 호출하면 쓰레드가 시작되고, run()메서드가 호출됨
package ch20;
class MyThread extends Thread { // Thread의 모든 메서드 사용 가능
public void run() {
int i;
for(i = 0; i <= 200; i ++) {
System.out.print(i + "\t");
}
}
}
public class ThreadTest {
public static void main(String[] args) {
System.out.println(Thread.currentThread() + "start"); // 실행되는 thread 정보 출력
MyThread th1 = new MyThread();
MyThread th2 = new MyThread();
// 총 세개의 쓰레드 돌아감 (+ main 쓰레드)
th1.start(); // run 메서드 호출
th2.start();
System.out.println(Thread.currentThread() + "end");
}
}
Runnable 인터페이스와 run() 메서드를 구현
- Runnable 인터페이스를 implement해서 구현
- Runnable 인스턴스를 매개변수로 받는 Thread 클래스의 생성자를 이용하여 쓰레드 생성
class MyThread implements Runnable {
...
}
public class ThreadTest {
public static void main(String[] args) {
MyThread runnable = new MyThread();
Thread th1 = new Thread(runnable); // 매개변수 runnable 인스턴스
Thread th2 = new Thread(runnable);
}
- Runnable 익명 객체를 생성하여 쓰레드를 생성할 수도 있음
Runnable run = new Runnable() { // 익명 객체 생성 -> 쓰레드
@Override
public void run() {
System.out.println("run");
}
};
run.run();
Thread Status

- 쓰레드가 시작되면 쓰레드 풀(pool)에 들어옴 → Runnable 상태 : CPU를 배분 받으면 바로 실행 가능한 상태
- 쓰레드가 종료되면 Dead 상태로 전환
- Not Runnable 상태 : CPU를 점유할 수 없는 상태 (계속 남아있으면 좀비 쓰레드)
- 자바의 상태전이 메서드
- sleep(time) : 지정된 시간동안 Not Runnable 상태. 시간이 지나면 Runnable 상태로 돌아옴
- wait() : 리소스가 available할 때까지 Not Runnable 상태. notify() 메서드를 호출하면 Runnable 상태로 돌아옴.
- join() : 하나의 쓰레드가 다른 쓰레드의 결과를 참조할 때, 참조하는 쓰레드는 다른 쓰레드가 끝날 때까지 Not Runnable 상태. 참조되는 쓰레드가 끝날 때 Runnable 상태로 돌아옴.
- wait()이 호출되고 notify()가 호출되지 않거나, join()의 경우 다른 쓰레드가 종료되지 않으면 Not Runnable에 계속 남아있게 됨 → 좀비 쓰레드 상태
'Java' 카테고리의 다른 글
| [Java 기능] Thread 클래스의 여러 메서드 (0) | 2022.02.18 |
|---|---|
| [Java 기능] Decorator Pattern 활용한 커피머신 프로그램 (0) | 2022.02.17 |
| [Java 기능] 그외 여러가지 입출력 클래스들 (0) | 2022.02.17 |