Hyunebee

Thread 본문

Java/Java의 정석

Thread

Hyunebee 2022. 3. 13. 18:16

Thread 

쓰레드의 구현은 크게 2가지로 구분

-Thread의 클래스를 상속받아서 구현

-Runnable의 인터페이스를 구현 

 

둘의 차이점

Runnable 인터페이스를 구현한 경우

Runnable을 구현한 클래스의 인스턴스를 생성한 다음, 이 인스턴스를 Thread클래스의 생성자의 매개변수로 제공한다. 

 

Thread 클래스의 문서이다.

 

class ThreadEx1 {
    public static void main(String args[]) {
        ThreadEx1_1 t1 = new ThreadEx1_1();

        Runnable r  = new ThreadEx1_2();
        Thread   t2 = new Thread(r);     // 생성자 Thread(Runnable target)

        t1.start();
        t2.start();
    }
}

class ThreadEx1_1 extends Thread {
    public void run() {
        for(int i=0; i < 5; i++) {
            System.out.println(getName()); // 조상인 Thread의 getName()을 호출
        }
    }
}

class ThreadEx1_2 implements Runnable {
    public void run() {
        for(int i=0; i < 5; i++) {
            // Thread.currentThread() - 현재 실행중인 Thread를 반환한다.
            System.out.println(Thread.currentThread().getName());
        }
    }
}

위의 코드를 보면 알 수 있듯이 Thread를 상속받아 구현한 객체는 new 연산자로 인스턴스를 생성한뒤 start()로 실행하지만 Runnable을 사용해 구현해 생성한 인스턴스는 Thread 클래스의 생성자로 다시 넣어줘야한다. 

 

Start()

위의 코드들을 보면 쓰레드를 생성했다고 해서 바로 실행되지 않는다. .start()를 호출해야만 쓰레드가 실행된다. 이 또한 바로 실행되는것이 아니라 우선순위에 따라 실행된다. 그리고 한번 종료된 쓰레드는 다시 실행할 수 없다. 즉 하나의 쓰레드에 대해 start()는 한번만 호출 가능하다는 것이다. 다시 호출하기위해서는 새로운 쓰레드를 생성한뒤 다시 호출해야 한다. 

 

Start() vs Run() 

둘의 차이는 그러면 무엇일까?

run()을 호출하는 것은 생성된 쓰레드를 실행시키는 것이 아니라 단순히 클래스에 선언된 메서드를 호출하는 것 run() 만 사용하게 된다면 해당 호출스택에 바로 올라간다 새로운 호출스택을 생성하지 않는다. 

 

start()을 호출하는 것은 새로운 쓰레드가 작업을 실행하는데 필요한 호출스택을 생성한 다음에 run을 호출해서 생성된 호출스택에 올려준다. 

 

 

ex)

 

main쓰레드에 start()를 호출

main 메소드에서 start 호출 호출스택을 생성 - (쓰레드는 독립적인 작업을 수행하기 위해 자신만의 호출스택이 필요 ) 생성된 호출 스택에 run을 올려줌 이제 두개의 쓰레드를 스케쥴러가 우선순위를 판단해서 수행 작업이 끝나면 호출스택은 사라지게됨 

 

데몬쓰레드

데몬 쓰레드는 다른 일반 쓰레드의 작업을 돕는 보조적인 역할을 수행하는 쓰레드이다. 기능 일반쓰레드와 같은 기능을 한다. 데몬 쓰레드는 일반 쓰레드와 다르게 실행하기 전에 setDaemon(true)을 호출하기만 하면 된다. 그리고 데몬쓰레드에서 생성된 쓰레드 또한 데몬쓰레드이다. 

 

class ThreadEx10 implements Runnable  {
    static boolean autoSave = false;

    public static void main(String[] args) {
        Thread t = new Thread(new ThreadEx10());
        t.setDaemon(true);    // 이 부분이 없으면 종료되지 않는다. 
        t.start(); //setDaemon(true)는 항상 start이전에 쓰여야한다.

        for(int i=1; i <= 10; i++) {
            try{
                Thread.sleep(1000);
            } catch(InterruptedException e) {}
            System.out.println(i);

            if(i==5)
                autoSave = true;
        }

        System.out.println("프로그램을 종료합니다.");
    }

    public void run() {
        while(true) {
            try {
                Thread.sleep(3 * 1000);    // 3초마다
            } catch(InterruptedException e) {}

            // autoSave의 값이 true이면 autoSave()를 호출한다. 즉 i가 5가된 이후에 3초마다 한번씩 자동으로 저장된다.\
            // i의 값이 최대값은 10으로 총 2번 저장된다.
            if(autoSave) {
                autoSave();
            }
        }
    }

    public void autoSave() {
        System.out.println("작업파일이 자동저장되었습니다.");
    }
}

'Java > Java의 정석' 카테고리의 다른 글

쓰레드의 실행과 제어  (0) 2022.03.15
싱글 쓰레드 멀티 쓰레드  (0) 2022.03.15
Enum  (0) 2022.03.12
제네릭스(Generics)  (0) 2022.03.09
Set, Map  (0) 2022.03.08