Thread & Runnable

Java/Threads 2013. 2. 7. 13:18

Thread 프로그램 생성 방식

 

Java에서는 두 가지 방식으로 thread를 생성할 수 있습니다.

1. Thread Class를 상속
2. Runnable Interface를 구현

Thread Runnable에 모두 선언되어 있는 void run() 메소드를 사용자는 오버라이드 하여 해당 작업을 기술하게 됩니다.

또한 run() 메쏘드는 Thread 클래스의 Start()메쏘드에 의하여 호출 되기 때문에 따로 호출하지 않아도 됩니다.

Thread Runnable의 차이는 Class Interface에서도 볼 수 있다시피 "상속"의 차이 입니다.
기본적으로 Java는 다중상속을 금지하고 있습니다.
따라서, A라는 클래스가 B 클래스를 상속받아야 하며, A가 쓰레드로 동작되어야 할 경우,
Runnable implement하면 됩니다.

Runnable은 오로지 run() 메쏘드만 정의되어 있으므로, 쓰레드에 대하여 다른 작업이 필요할 경우,
생성할 때
Thread t = new Thread(정의한 Runnable);
 형태로 생성하여 사용하여야 합니다.

아래는 위 설명에 대한 예제 code 입니다.

 

 

public class MyThread extends Thread {

    @Override

    public void run() {

        System.out.println("Hello, MyThread");

    }

}

 

 

public class MyRunnable implements Runnable {

    @Override

    public void run() {

        System.out.println("Hello, MyRunnable");

    }

}

 

 

public class MyTest {

   public static void main(String[] args) {

       Thread t1 = new Thread(new MyRunnable());

       t1.start();

                

       MyThread t2 = new MyThread();

       t2.start();

   }

}

 

 

출처 : http://truth4u.tistory.com/62

참조 : http://stevenjsmin.tistory.com/24 [ Thread Socket 프로그램 ]

 





다른 유용한 글

http://blog.naver.com/hyoun1202/90192727041



 Multi-Thread 구현하는 방법은 2가지가 있다.

 

1. java.lang.Thread 클래스를 상속받아서 구현하는 방법

    *   장점 : Thead 클래스의 메소드를 바로 사용 가능함 
    *  
단점 : 대상 클래스가 다른 클래스로부터 상속받아야하는 경우 사용할 없음  

2, java.lang.Runnable 인터페이스를 구현해서 개발하는 방법

    *   장점조상(또는 공통클래스로부터 상속받은 자손 클래스들도 Thread 사용 가능 
    *  
단점 : 스레드 클래스의 메소드 사용 불가

   Thead 클래스의 메소드들에 대한 정보는 http://ra2kstar.tistory.com/130 참조

 

다음은 1, 2 방법으로 각각 구현된 클래스들의 소스 코드와 이들을 실행하는 메인 함수의 소스 코드는 다음과 같다.



1. 메인 함수의 소스코드 

package sample.multithread;


public class MultiThreadExam {

/**

 * Multi-Thread Example<br>

 * [Multi-Thread 구현] 멀티 스레드를 구현하는 2가지 방법은 다음과 같다.<br>

 * 1. java.lang.Thread 클래스 이용 

         *         장점 : 스레드 클래스의 메소드를 바로 사용 가능함 

         *         단점 : 대상 클래스가 다른 클래스로부터 상속받아야하는 경우 사용할 수 없음<br>

 * 2. java.long.Runnable 인터페이스 이용 

         *         장점 : 다른 클래스로부터 상속받은 클래스도 스레드로 사용 가능 

         *         단점 : 스레드 클래스의 메소드 사용 불가

 

 * @author 황철연

 */

public static void main(String[] args) {


// 1번 방식으로 구현된 클래스 실행하기

ThreadExam threadExam = new ThreadExam();

threadExam.start();


// 2번 방식으로 구현된 클래스 실행하기

RunableExam runableExam = new RunableExam();

Thread runableExamTh = new Thread(runableExam);

runableExamTh.start();

}

}


 


2-1. 1 방법으로 구현된 클래스의 소스 코드 

package sample.multithread;

import java.awt.AWTException;

import java.awt.Robot;


public class ThreadExam extends Thread {


    // 핵심코드

    public void run() {

   mainJob();

    }


    public void mainJob() {

  for (int i = 0; i < 5; i++) {

System.out.println("ThreadExam.mainJob() 호출 : " + i);

setTimerOn(4); // 3초 Delay - 테스트용 함수

}

    }


    /**

     * 테스트용 함수 지정된 시간 동안 프로세스를 sleep시킨다.

     

     * @param timer 지연시간(단위:초)

     */

    protected boolean setTimerOn(int timer) {  


Robot tRobot;

int delayTime;

boolean result;

delayTime = timer * 1000; // mm초 단위에 맞도록 *1000을 한다.


try {

    tRobot = new Robot();

            // delay() 함수를 이용하여 delayTime 밀리초 동안 프로세스를 sleep 상태로 만든다.

    tRobot.delay(delayTime); 

    result = true;


} catch (AWTException e) {

    System.out.println(this.getClass().getName() + ",setTimerOn(" + timer + ")오류");

    result = false;

}


return result;

    }

}



 


2-2.  2 방법으로 구현된 클래스의 소스 코드 

package sample.multithread;

public class RunableExam extends AbstractBean implements Runnable {

    /**

     * Runnable 인터페이스 구현시 반드시 새로 정의해야( Overriding) 하는 함수 

     * @see java.lang.Runnable#run()

     */

     public void run() {

         mainJob();

     }

 

     public void mainJob(){

         for (int i = 0; i < 5; i++) {  

     System.out.println("RunableExam.mainJob() 호출 : " + i);  

     setTimerOn(3); //3초 Delay - 테스트용 함수

 }

     }

}



 


 RunableExam 클래스에서 상속받은 조상 클래스의 소스 코드


package sample.multithread;

import java.awt.AWTException;

import java.awt.Robot;


public class RunableExam extends AbstractBean implements Runnable {

    /**

     * 테스트용 함수 

     * 지정된 시간 동안 프로세스를 sleep시킨다.

     * @param timer 지연시간(단위:초)

     */ 

     protected boolean setTimerOn(int timer){ 

     

         Robot tRobot;

         int delayTime;

         boolean result;

         delayTime = timer * 1000; // mm초 단위에 맞도록 *1000을 한다.

     

         try {

             tRobot = new Robot();

             // delay() 함수를 이용하여 delayTime 밀리초 동안 프로세스를 sleep 상태로 만든다.

             tRobot.delay(delayTime);

             result = true;


         } catch (AWTException e) {

             System.out.println(this.getClass().getName()+ ", setTimerOn(" + timer + ") 오류");

             result = false;

         }

        

         return result;

     }

}

 

MultiThread 기존 Thread 관련없는 별도의 독립적인 Thread 실행시키므로 이들의 결과값을 리턴받는 방법이 까다롭다.

상기 예제의 경우 메인함수가 각각의 Thread 실행시킨 Thead 처리결과를 return 받을 없게된다. 왜냐면 각각의 Thread 메인함수가

실행중인 Thread와는 별개로 생성된 신규 Thread에서  각각 실행되기때문이다.

 

코드로 설명하면...

public static void main(String[] args) {
 

    String rtn1 = '0';

    String rtn2 = '0';     


    ThreadExam threadExam = new ThreadExam();
    threadExam.start();

    rtn1 = threadExam.getResult();
  
    RunableExam runableExam = new RunableExam();
    Thread runableExamTh = new Thread(runableExam);
    runableExamTh.start();

    rtn2 = runableExam.getResult();

   

    System.out.println(  rtn1 + "," + rtn2 );


 }

 

상기 예에서 ThreadExam  RunableExam 쓰래드가 정상적으로 실행 완료된 후의 결과값으로 각각(getResult() 반환값) '1' 반환 한다고

가정해보자. 이때 코드에서 System.out.println() 결과가 과연 '1,1' 찍힐까아니다. 결과는 '0,0'으로 찍힌다.

이유는 앞서 말했듯이 Thread main() 함수에 얽매이지 않고 독립적으로 실행되므로 main() 함수의 코드는 그냥 밑으로 흘러내려버린다.

그래서 '0,0' 찍히고 main() 함수의 실행은 종료된다. 그러나 ThreadExam RunableExam 쓰래드는 각각 독립적으로 실행되다가 종료될 것이다.

그럼 Thread 실행 결과를 Thread 실행한 객체에서 잡아내려면 어떻게 해야 할까? 이때 join() 함수를 사용하면 된다.

코드를 다음과 같이 변경해 보자.

public static void main(String[] args) {


    String rtn1 = '0';

    String rtn2 = '0';


    ThreadExam threadExam = new ThreadExam();
    threadExam.start();

 

    RunableExam runableExam = new RunableExam();
    Thread runableExamTh = new Thread(runableExam);
    runableExamTh.start();

 

    //Thread 상태 점검
    System.out.println( "ThreadExam isAlive  : " + threadExam.isAlive() );
    System.out.println( "RunableExam isAlive : " + runableExamTh.isAlive() );
  
    try {
         //join
Thread 끝날때까지 대기!
         threadExam.join();
         runableExamTh.join();


    } catch (InterruptedException e) {
         e.printStackTrace();
    }

     

    rtn1 = threadExam.getResult();

    rrn2 = runableExam.getResult();

    //Thread 최종결과반환

    System.out.println( rtn1 + "," + rtn2 );
      
    //Thread
상태 점검
    System.out.println( "ThreadExam isAlive  : " + threadExam.isAlive() );
    System.out.println( "RunableExam isAlive : " + runableExamTh.isAlive() );

}

 

코드의 핵심은 Thead.join() 함수이다. join 해주면 해당 쓰래드가 살행 완료될 때까지 main() 메소드가 기다리게된다. ThreadExam 

RunableExam  쓰래드는 이전과 같이 별개의 Thread 각각 독립적으로 실행되지만 각각의 쓰래드가 실행 완료 될때까지 main() 함수가 기다렸다가

이후 코드를 실행시킨다. 따라서 이때 main() 함수의 최종 결과값은 '1,1' 찍히게 된다.

추가로 상기 코드에서 새로 추가된 Thead.isAlive() 함수는 해당 쓰래드가 실행중인지 아닌지를 체크할 사용한다. 코드에서는 Thread 실행한

직후의  isAlive() 함수는 true 반환하고 실행 완료된 후에는 false 반환한다.

 

'Java > Threads' 카테고리의 다른 글

Thread Synchronization  (0) 2013.02.07
Controlling Thread Status  (0) 2013.02.07
Posted by Steven J.S Min
,