쓰레드(Thread)와 런에이블(Runnable) 1편
본 게시물은 jdk 1.8 기준으로 작성되었습니다.
1. 쓰레드(Thread)란?
프로그램을 실행하면 OS로부터 실행에 필요한 자원(메모리)를 할당 받아서 프로그램이 실행된다. 프로그램이 실행된 결과물이 바로 프로세스이다. 예를 들어 윈도우의 Ctrl + Shift + ESC를 하면 탭 부분에 프로세스가 보이는데 클릭해보면 실행 중인 프로세스 리스트가 보인다. 즉, 실행 중인 프로그램 = 프로세스!
- 프로세스 = 데이터(data) + 자원(memory) + 쓰레드(Thread) 로 구성되어서 실제로 프로그램이 실행되기까지는 쓰레드(Thread)가 바로 데이터(data)+자원(memory)를 활용하여서 작업을 수행한다.
- 쓰레드(Thread) 작업을 수행하려면 메모리 공간이 필요하므로 메모리의 한계에 따라서 최대로 생성할 수 있는 쓰레드 수가 결정된다.
- 모든 프로세스에는 최소한 하나 이상의 쓰레드(Thread)가 존재하며, 두 개 이상의 쓰레드(Thread)를 가지면 멀티-쓰레드(multi-threaded) 라고 한다.
2. 쓰레드(Thread) 구현하기
자바에서 쓰레드를 구현하는 방식은 Thread를 이용하는 방법과 Runnable을 이용하는 방법 2가지가 있다. Thread 클래스는 상속(Extends)를 받아서 사용해야 하므로 다른 클래스들을 상속받을 수 없다. (자바는 기본적으로 다중상속 금지) 그러나 Runnable 인터페이스는 구현(implements) 받아서 사용하므로 필요하다면 다른 클래스를 상속받아서 재사용성과 코드의 일관성을 높일 수 있다. 또한 Thread 를 한번 사용하면 재사용이 불가능하지만, Runnable 를 이용하여 Thread를 구현하면 재사용할 수 있다.
잘 와닿지 않을테니 아래의 예제를 통해서 내용을 확인하자. 혹시 이 게시물을 읽기전 상속(Extends)와 구현(implement), 인터페이스 클래스 등을 잘 모르겠다면 'http://aileen93.tistory.com/107' 이전 게시물 참고!
[방법 1] Thread로 쓰레드 구현하기
예제 1
package ch13_Thread;
class ThreadEx01 {
public static void main(String args[]) {
ThreadEx2 t1 = new ThreadEx2();
t1.start();
}
}
class ThreadEx2 extends Thread {
// 쓰레드를 통해서 수행할 내용들을 정의
public void run() {
// 작업내용
for(int i=0; 5 > i; i ++)
System.out.println("쓰레드가 실행되었습니다.");
}
}
쓰레드가 실행되었습니다.
쓰레드가 실행되었습니다.
쓰레드가 실행되었습니다.
쓰레드가 실행되었습니다.
쓰레드가 실행되었습니다.
여기서 의문이 생길 것이다. run으로 구현되어있는데, 왜 start로 Thread를 실행 시키는지!
Thread 클래스의 메소드 API 문서를 확인해보자.
void | start() 이 스레드가 실행을 시작하도록합니다. Java 가상 머신 run 이 thread 의 메소드를 호출합니다 . |
void | run() 이 스레드가 별도의 Runnable 실행 객체 를 사용하여 작성된 경우 해당 Runnable 객체의 run 메소드가 호출됩니다. 그렇지 않은 경우, 이 메서드는 아무 것도 수행하지 않고 반환합니다. |
- start 메소드는 thread의 메소드를 호출하고, run메소드는 Runnable 실행 객체를 사용하여서 작성된 경우에만 Runnable의 run메소드가 호출된다고 적혀있다. 그러므로 Thread를 실행시킬 때에는 start메소드를 통해서 실행시켜야하며, run을 통해서도 실행은 되지만 정확히는 Thread를 이용하여 실행시킨 것은 아니다.
- 1번의 내용을 더 자세하게 설명 하자면 JVM의 Call stack 메모리를 생각해보자. 쓰레드를 사용하기 위해서는 쓰레드 만의 독립적인 작업 공간(Memory)가 할당된 후 Call stack이 만들어진다. 그 후에 Call stack 안에 각 실행하고자 run()과 같은 메소드들이 올라가게 되고 Call stack에 있는 내용들이 모두 실행이 되고 나면 쓰레드는 작업 공간을 반환되며 메모리가 소멸된다. 그러므로 쓰레드를 정확히 사용하기위해서는 Start() 메소드를 사용하여야 한다.
[방법 2] Runnable로 쓰레드 구현하기
class RunnableImplements implements Runnable {
// Runnable인터페이스의 추상메서드 run()을 구현
public void run() {
// 작업내용
}
}
- Thread와 다른 점은 Runnable 클래스를 implements하였다는 점이다.
- 그러므로 Thread보다 더 확장성 있는 코드를 만들 수 있다. (오버로딩하여서 작성하여야하므로)
예제 2
package ch13_Thread;
// view-source:https://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html
class RunnableEx01 {
public static void main(String args[]) {
Runnable r = new ThreadEx1();
Thread t1 = new Thread(r);
t1.start();
}
}
class ThreadEx1 implements Runnable {
// 스레드를 종료시키기 위한 플래그 변수
private boolean stopped = false;
// 스레드를 통해서 실행시킬 task 로직
public void run() {
while (!stopped) {
System.out.println("Thread is alive :"+ stopped);
try {
System.out.println("active.."+Thread.activeCount());
Thread.sleep(2000);
} catch (Exception e) {
stop();
}
stop();
}
}
// 스레드 종료시키기
public void stop(){
System.out.println(Thread.currentThread().getName()+"가 종료되었습니다.");
stopped = true;
}
}
3. 결론
Thread보다 Runnable이 더 확장성(유연성)있는 코드 작성이 가능하다.
Runnable의 단점은 그럼 무엇일까?..
*쓰레드(Thread)와 런에이블(Runnable) 2편