코린이의 소소한 공부노트

쓰레드의 구현 방법과 실행 본문

Java

쓰레드의 구현 방법과 실행

무지맘 2022. 11. 30. 00:07

[쓰레드의 구현 방법]

아래 두 가지 방법 중 하나를 선택한 후 run()에 쓰레드로 작업하고자 하는 내용을 채운다.

1. Thread 클래스를 상속받는다.

class MyThread1 extends Thread{
    public void run(){ // Thread 클래스의 run() 오버라이딩
        for(int i=0; i < 5; i++)
            System.out.println(getName());
            // 조상인 Thread의 getName()을 호출
            // this.getName()에서 this가 생략된 형태
    }
}

2. Runnable 인터페이스를 구현한다. (권장. 자바는 단일 상속)

public interface Runnable{
    public abstract void run();
}

class MyThread2 implements Runnable{
    public void run() {  // Runnable 인터페이스의 추상 메서드 run() 구현
        for(int i=0; i < 5; i++)
            // 인터페이스를 구현한 것이기 때문에 getName에 다음과 같이 접근한다.
            // Thread.currentThread() - 현재 실행중인 Thread를 반환한다.
            System.out.println(Thread.currentThread().getName());
    }
}

 

[쓰레드의 실행]

// 쓰레드 생성
// 1. Thread 클래스를 상속받은 경우
MyThread1 t1 = new MyThread1();

// 2. Runnable 인터페이스를 구현한 경우
Runnable r = new MyThread2();
Thread t2 = new Thread(r); // 생성자 Thread(Runnable target)
// 위 두줄의 코드를 한 줄로 줄이면 다음과 같다.
// Thread t2 = new Thread(new MyThread2());

t1.start(); // 쓰레드 실행
t2.start();

// 결과
Thread-0
Thread-0
Thread-0
Thread-0
Thread-0 // 여기까지가 t1.start()의 결과
Thread-1
Thread-1
Thread-1
Thread-1
Thread-1 // 여기까지가 t2.start()의 결과

- 위의 예시에서 반복 횟수를 늘린 멀티 쓰레드 실행

class ThreadEx1_1 extends Thread { // Thread 클래스 상속
    public void run() {
        for(int i=0; i < 100; i++)
            System.out.print(0);
    }
}

class ThreadEx1_2 implements Runnable { // Runnable 인터페이스 구현
    public void run() {
        for(int i=0; i < 100 ; i++)
            System.out.print(1);
    }
}

// main()
ThreadEx1_1 t1 = new ThreadEx1_1();
Runnable r = new ThreadEx1_2();
Thread t2 = new Thread(r);
t1.start();
t2.start();
// 결과
0000001111...00000111111000000001111
// 0과 1이 번갈아가면서 100개씩 출력된다
// t1과 t2중 무엇이 먼저 시작될지는 OS스케줄러가 결정한다.

- run()의 작업들을 전부 main()으로 옮겨서 싱글 쓰레드로 실행

for(int i=0; i < 100; i++) 
    System.out.print(0);
for(int i=0; i < 100 ; i++)
    System.out.print(1);
// 결과
0000...0000011111...1111111
// 0이 100개 먼저 출력되고 1이 100개 출력된다.

 

[실행 메서드 - start(), run()]

1. 쓰레드를 생성한 후 start()를 호출해야 쓰레드가 작업을 시작한다.

  - start()를 실행한다고 바로 실행되는 것이 아니라, 실행 가능 상태로 되는 것뿐이다.

  - OS스케줄러가 실행 순서를 결정하고, 실행 시간도 결정한다.

TereadEx1_1 t1 = new TereadEx1_1(); // 쓰레드 t1 생성
TereadEx1_1 t2 = new TereadEx1_1(); // 쓰레드 t2 생성
t1.start(); // 쓰레드 t1 실행
t2.start(); // 쓰레드 t2 실행
// t1, t2 중 어느 것이 먼저 실행될지 모른다.

2. start()를 호출한 후 run()을 호출해야 독립적인 수행(쓰레드 실행)이 가능해진다.

main()에 생성된 쓰레드가  start()를 실행하면 호출스택(call stack)에서 일어나는 일


[쿠키글] main 쓰레드

1. main()의 코드를 수행하는 쓰레드

  - 위의 그림에서 첫 번째 호출 스택을 main 쓰레드로 봐도 좋다.

2. 쓰레드는 ‘사용자 쓰레드’와 ‘데몬 쓰레드(보조 쓰레드)’ 두 종류가 있다.

3. 실행 중인 사용자 쓰레드가 하나도 없을 때 프로그램은 종료된다.

  - 위 그림에서 main 쓰레드가 종료돼도 run 쓰레드가 살아있다면 프로그램은 종료되지 않는다.

 

예시를 통해 main 쓰레드의 실행 종료와 프로그램 종료의 차이를 살펴보자.

// ThreadEx1 클래스의 run()
for(int i=0; i < 30; i++) {
    System.out.print(0);

// ThreadEx2 클래스의 run()
for(int i=0; i < 30; i++) {
    System.out.print(1);
    
// 3-1) main()에서 쓰레드를 그냥 실행시킨 경우
long startTime = 0;
ThreadEx1 th1 = new ThreadEx1();
ThreadEx2 th2 = new ThreadEx2();
th1.start();
th2.start();
startTime = System.currentTimeMillis();
System.out.print("소요시간:" + (System.currentTimeMillis() - startTime));
// 결과
소요시간:01110000000000000000000011111111111111111
-> main() 종료 -> t1 실행 종료 -> t2 실행 종료 -> 프로그램 종료

// 3-2) main()에서 쓰레드 종료를 기다리게 한 경우
long startTime = 0;
ThreadEx1 th1 = new ThreadEx1();
ThreadEx2 th2 = new ThreadEx2();
th1.start();
th2.start();
try {
    th1.join();	// main쓰레드가 th1의 작업이 끝날 때까지 기다린다.
    th2.join();	// main쓰레드가 th2의 작업이 끝날 때까지 기다린다.
} catch(InterruptedException e) {}
startTime = System.currentTimeMillis();
System.out.print("소요시간:" + (System.currentTimeMillis() - startTime));
// 결과
1111111111100111111111000000000000000000소요시간:3
-> t2 실행 종료 -> t1 실행 종료 -> main() 종료 -> 프로그램 종료

 

'Java' 카테고리의 다른 글

쓰레드의 우선순위와 그룹  (0) 2022.11.30
싱글쓰레드와 멀티쓰레드의 실행  (0) 2022.11.30
쓰레드의 정의  (0) 2022.11.24
애너테이션 만들기  (0) 2022.11.21
애너테이션의 정의와 종류  (0) 2022.11.17