13-2. 쓰레드의 구현과 실행

Hyun Jun·2022년 2월 7일
0

자바의 정석

목록 보기
45/52
post-thumbnail
post-custom-banner

쓰레드의 구현과 실행

쓰레드를 구현하는 방법은 2가지

  1. Thread 클래스 상속 받기

  2. Runnable 인터페이스 구현하기

두 방법 모두 run()이라는 메서드를 구현하는 것으로 끝.

run()의 구현부에는 쓰레드로 작업하고자 하는 내용을 넣으면 됨.

다만, 1번을 사용하면 다른 클래스를 상속받을 수 없게 된다는 제약이 있어, 일반적으로 2번 방법을 사용함.

 

그런데 Thread 클래스를 상속 받는 경우와 Runnable 인터페이스를 구현하는 경우는 인스턴스 생성 방식이 다름

class ThreadExample {
    public static void main(String[] args) {
        ThreadA a = new ThreadA(); // 일반적인 인스턴스 생성 방법과 동일

        Runnable r = new ThreadB(); // 우선 Runnable을 구현한 클래스의 인스턴스를 생성하고,
        Thread b = new Thread(r); // Thread의 생성자에 매개변수로 넘겨줘야함.

        a.start();
        b.start();
    }
}

class ThreadA extends Thread {
    public void run() {
        System.out.println(getName()); // (1)
    }
}

class ThreadB implements Runnable {
    public void run() {
        System.out.println(Thread.currentThread().getName()); // (2)
    }
}

실행 결과)

Thread-0
Thread-1

💡 왜 Runnable 구현체의 인스턴스를 Thread의 생성자 매개변수로 넘기는가?

ThreadB처럼 인스턴스를 생성한 후에 그걸 Thread의 생성자에 매개변수로 넘기는 이유는 객체지향 프로그래밍에서 추구하는 캡슐화와 관련되어 있음.

Thread 클래스를 단순화시켜 표현하면 다음과 같은데,

public class Thread {
    private Runnable r;

    public Thread(Runnable r) {
        this.r = r; // Runnable 구현 클래스의 인스턴스를 생성자의 매개변수로 받아와 Thread의 인스턴스 변수 값으로 지정.
    }

    public void run() {
        if (r != null) r.run(); // Runnable 구현 클래스의 인스턴스가 가진 run 메서드를 호출
    }
}

Runnable 구현체가 가진 run() 메서드는 선언부가 Runnable에서 정의한 run()의 선언부와 동일하게 되어 있어, 호출하는 입장에서는 인터페이스에 정의된 선언부만 확인하면 됨.

만약 ThreadBRunnable을 구현하지 않고, Thread의 생성자가 직접 ThreadB의 인스턴스를 매개변수로 받아왔다면 ThreadB가 가진 run()을 호출하는데에 있어 번거로움이 생김. run()의 선언부에 변경 사항이 생기면 그것을 호출하는 Thread쪽에서도 변경 사항에 맞게 수정을 해야하고, ThreadB가 아닌 다른 클래스를 사용하고자 할 때 다시 그 클래스의 메서드 스펙에 맞게 호출 파트를 수정해야함.

따라서 Runnablerun()을 호출하는 쪽과 구현하는 쪽이 직접적 의존 관계에 있지 않게 하고, 둘 사이의 중간 다리 역할이자 run() 메서드 선언을 표준화 시키는 역할을 함.

 

💡 getName()을 호출하는 방식이 왜 다른가?

Thread를 상속받은 ThreadAThread가 가진 메서드를 직접 호출해서 자유롭게 사용할 수 있지만 (주석 1번)

Thread를 상속받지 않은 ThreadBThread의 static 메서드인 currentThread()로 현재 실행중인 쓰레드의 참조를 얻어온 상태에서만 Thread의 메서드를 사용할 수 있음. (주석 2번)

 

💡 쓰레드의 이름은 바꿀 수 없는가?

쓰레드의 이름은 기본적으로 Thread-0, Thread-1, Thread-2, ... 지만

  1. Thread 생성자에 이름을 지정해주거나,

    Thread(Runnable r, String name)
    Thread(String name)
  2. setName() 메서드로 이름을 지정해주면 바꿀 수 있음

    void setName(String name)

 

쓰레드의 실행 - start()

쓰레드를 생성한 이후에 start()을 호출해야 실행시킬 수 있음.

start()이 호출되면, 해당 쓰레드는 실행 대기 상태에 들어갔다가 자기 차례가 오면 실행됨. (대기자가 없으면 바로 실행)

 

❗️ [주의]

실행 종료된 쓰레드는 다시 실행할 수 없음.

따라서 한 쓰레드에 대해 start()은 한 번만 쓸 수 있으며, 같은 쓰레드를 다시 실행시키려면 쓰레드 인스턴스를 새로 생성한 다음에 start()을 다시 호출해야함.

ThreadA a = new ThreadA();
a.start();

a = new ThreadA(); // 새 인스턴스를 생성하고 참조변수에 재할당
a.start();
profile
Back-end Engineer 👨‍💻
post-custom-banner

0개의 댓글