"Thread에게는 Runnable객체가 필요하다" 는 사실입니다.
Thread가 Thread로서 삶을 시작할 때 시작하는 일이 Runnable의 public void run() 메소드
를 수행하는 것이기 때문입니다.
즉,Runnable객체의 public void run() 메소드는 Thread로 하여금 원하는 일을 시킬수 있는
거의 유일한 방법인 셈입니다. Thread가 수행해야할 일을 Runnable의 public void run()에
써주는 겁니다.
관심이 있는 분들은 혹 아실지 모르지만 Thread클래스를 살펴보면 Thread 클래스에도
public void run()가 있습니다. 그렇다면 Thread도 Runnable인가요? 예 그렇습니다.
모든 Thread는 Runnable 입니다. 이것이 의미하는 뜻은 Thread가 생성자에서 Runnable
객체를 인자로 받게 되면 , Thread는 Thread로서 삶을 시작할 때 생성자에서 받은
Runnable의 public void run()을 수행합니다. 하지만 만약 생성자에서 Runnable객체를 인자
로 받지 못하면, 스스로가 Runnable객체이므로, Thread가 가진 public void run()을 실행
하게 된다는 뜻입니다. 이와 같이 어쨌든 Thread가 해야할 일을 지정해주는 것은
Runnable 객체입니다.
따라서 Thread를 이용하는 프로그램을 해야 하는 경우 크게 두가지 방법이 있는데
그 첫째는 Thread가 수행해야할 일인 Runnable 객체를 별도로 만들어 public void run()
메소드를 원하는 대로 만드는 것이고,
둘째는 Thread 자체가 Runnable객체이므로 Thread를 상속한후 public void run() 메소드를
원하는 대로 고치는 겁니다
즉, Runnable 객체를 만들지 않고 Thread를 상속해서 public void run()메소드를 오버라이딩
한다는 뜻입니다. 즉, Runnable객체의 public void run()에서 적어주여할 일들을 모두 적어
주게 되면 되는 것이지요.
물론 2가지 방법중 어떤 것을 사용해도 원하는 결과를 얻는데는 크게 다르지 않습니다.
하지만 필자는 수행해야 하는 일을 거의 Runnable객체를 정의하고 Thread는 Runnable
객체를 수행하는 도구로 사용하고만 있습니다.
여기에는 상당한 이유가 있는데, Runnable객체는 독립적으로 수행되야할 일의 개념화 및
모듈화를 의미합니다. Thread는 단순히 그 일을 독립적으로 수행하는 단순한 도구로써
사용하는 것입니다. 실제로 일을 하는 프로그램 코드(Runnable 객체에 담긴 내용)를
코드와는 전혀 상관도 없고, 아무 연관관계도 없는 Thread 클래스에 합쳐서 관리할 이유가
없기 때문이고, 오히려 이런 관계없는 것을 철저히 분리시켜 놓는 것이 가독성이라던가
코드의 관리에 아주 도움이 되기 때문입니다.
하지만 이는 절대적인 것은 아니고, 가끔 편의성에 따라 필자도 Thread 클래스를 상속
해서 사용하곤 합니다. 하지만 독자분에게 권하는 바는 특별한 이유가 없는한 Runnable
객체를 이용하는 것을 먼저 고려하시라는 것입니다.
Thread와 Runnable객체
예제 7-6 과 7-7은 아주 간단한 Runnable클래스입니다.
public class AsiaRunnable implements Runnable {
public void run() {
for(int i = 0; i < 10; i++)
System.out.println("Tiger " + i );
}
}
예제 7-6 AsiaRunnable.java
public class AfricaRunnable implements Runnable {
public void run() {
for(int i = 0; i < 10; i++)
System.out.println("Zebra " + i );
}
}
예제 7-7 AfricaRunnable.java
AsiaRunnable 과 AfricaRunnable는 모두 Runnable 인터페이스를 구현했습니다.
Runnable의 가장 중요한 요소인 public void run() 메소드에서는 각각 대륙의 대표적인 동물
인 호랑이와 얼룩말을 화면에 10번씩 출력하는 내용을 담고 있습니다.
AsiaRunnable과 AfricaRunnable은 Runnable이기 때문에 Thread를 이용한 프로그램에서
당당히 사용될 수 있는 것이고, Thread와 결합한후 Thread가 시작되게 되면 Thread는
Runnable의 public void run()을 수행하기 때문에 AsiaRunnable과 결합한 Thread는 호랑이
를 AfricaRunnable과 결합한 Thread는 얼룩말을 출력합니다.
public class RunnableThread {
public static void main(String[] args ) {
Runnable
new Thread(
AsiaRunnable
new Thread(
System.out.println("main thread done");
}
}
예제 7-9 RunnableThread.java
예제 7-9는 Runnable객체와 Thread를 어떻게 사용하는지에 대한 가장 간단한 예를
나타냅니다.
이제는 폴리포피즘에 대해서 익숙하시겠지요. 예제 7-9에는 폴리포피즘을 이용한 부분이
있는데 바로 Runnable africa = new AfricaRunnable() 입니다.
AfricaRunnable역시 Runnable이기 때문에 이런 코드가 가능한 거지요.
RunnableThread를 실행시킨 경우에는 최소의 Main Thread뿐만 아니라 2개의 Thread가
더 만들어 집니다. 즉 AfricaRunnable의 public void run()을 수행하는 Thread와
AsiaRunnable의 public void run()을 수행하는 Thread가 그것입니다.
예제 7-9에서 Thread를 사용한 것을 보면 Thread를 만들고, 생성자에 Runnable 객체인
AfricaRunnable을 Thread 생성자에 인자로 주고,Thread의 start() 메소드를 호출합니다.
Thread의 삶의 주기를 살펴볼 때 좀 더 언급하겠지만 new 를 통해 만들어진 Thread
객체는 그 자체로는 큰 의미가 없습니다. Thread객체의 start()를 호출한 후에야 비로서
Thread는 Thread로서 삶을 사는 것입니다. 즉, 스케쥴러로부터 CPU등의 시스템 자원을
얻을 수 있는 기회가 생기는 거지요.
예제 7-9에서는 Thread를 만드는 행동과 Thread를 시작시키는 행동을 한꺼번에 실행하고
있습니다. 보통의 경우는
Thread t = new Thread(
t.start();
이렇게 두 부분으로 나누어 사용하고 Thread에 대한 레퍼런스 t를 이용해서 thread를
제어하게 됩니다. 예제 7-9에서는 Thread를 만든다음 시작시키면 그 것으로 할일은 끝이기
때문에 Thread를 생성한후 곧 바로 실행도 했습니다.
그림 7 - 1
그림 7 - 1을 살펴보면 Main Thread가 만들어낸 2개의 Thread, Africa Thread와
Asia Thread는 동시에 경쟁하면서 실행되는 것을 볼 수 있습니다.
얼룩말 번호 사이에 호랑이 번호가 출력되는 것은 Africa Thread와 Asia Thread가 동시에
경쟁하면서 일을 수행하기 때문입니다.
만약 Thread가 경쟁하지 않고 순서대로 일을 수행한다면 얼룩말 번호가 모두 출력되고,
호랑이 번호가 출력되던가, 아니면 호랑이 번호가 먼저 출력이 되고 얼룩말 번호가 출력이
되어야 할텐데 경쟁하는 Thread가 동시에 일을 수행하고 있기 때문에 중간 중간에 출력의
순서가 뒤바뀌고 있습니다.
'자바 Threads Programming > Basic' 카테고리의 다른 글
Thread-6.Thread 우선순위 (0) | 2008.01.07 |
---|---|
Thread-5.Thread 라이프사이클(Life Cycle) (0) | 2008.01.07 |
Thread-4.간단한 Thread 검색 프로그램 (0) | 2007.12.28 |
Thread-3.Thread와 Thread의 상속 (0) | 2007.12.28 |
Thread-1.Thread (0) | 2007.12.18 |