Backend/Java

Thread 생성방식과 동작원리

간지나제 2021. 4. 23. 17:40

Thread 생성방식

기본적으로 Thread는 생성할 때 Runnable Interface의 run을 구현해야한다.
Thread 만드는 것을 여러 예시를 통해 볼텐데 결국에는 Runnable Interface의 run을 구현하는 것이다.
Thread class는 껍데기이고 Runnable Interface를 구현하는 곳에 로직이 들어간다.

1.Runnable Interface를 구현한 class를 이용하여 만든 Thread
2.Thread를 상속하여 만든 class를 이용해 만든 Thread
3.익명 객체를 이용하는 방법
4.Daemon Thread


Thread를 10개를 만들어서 1부터 10까지 찍는 예시를 한번 보자.

Runnable Interface를 구현한 class를 이용하여 만든 Thread


for(int i=0; i<10; i++) {
    Runnable r = new ThreadTest(i);
    Thread thread = new Thread(r);
    thread.start();
}

class ThreadTest implements Runnable {
    int seq;

    ThreadTest(int seq) {
        this.seq = seq;
    }

    @Override
    public void run() {
        System.out.println(seq);
    }
}

Thread를 상속하여 만든 class를 이용해 만든 Thread

Thread class안에 Runnable Interface를 implements하고 있다.


for(int i=0; i<10; i++) {
    Thread thread = new ThreadTest2(i);
    thread.start();
}

class ThreadTest2 extends Thread() {
    int seq;

    ThreadTest2(seq) {
        this.seq = seq;
    }

    @Override
    public void run() {
        System.out.println(seq);
    }
}

익명 객체를 이용하는 방법


for(int i=0; i<10; i++) {
    int finalI = i;
    // 생성자에 익명의 Runnable객체를 넣는 방식
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println(finalI);
        }
    });

    // 빈 생성자를 이용한 방식
    Thread thread = new Thread() {
        @Override
        public void run() {
            System.out.println(finalI);
        }
    };

    // 람다식을 이용한 방식
    Thread thread = new Thread(() => System.out.println(finalI);
}

Daemon-thread

daemon thread는 main thread의 작업을 보조하는 역할을 수행하는 스레드이다.
주 스레드가 종료되면 daemon thread는 존재 의미가 없기에 강제 종료된다.
예를 들어, 워드의 자동 저장 기능이 있다.
세팅하는 방법은 thread를 생성하고 setDaemon(true)로 설정할 수 있다.

public static void main(String[] args) {
        Thread daemon = new Thread(() -> {
            while(true) {
                System.out.println("데몬 스레드가 실행중....");
                try {
                    Thread.sleep(1);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        daemon.setDaemon(true);
        daemon.start();

        try {
            Thread.sleep(10);
        } catch (Exception e2) {
            e2.printStackTrace();
        }

        System.out.println("main thread 종료");
    }

위와 같은 코드를 실행하면 아래와 같이 daemon thread가 실행되다가 main thread가 종료됨과 동시에 daemon thread가 종료된다.

데몬 스레드가 실행중....
데몬 스레드가 실행중....
데몬 스레드가 실행중....
데몬 스레드가 실행중....
데몬 스레드가 실행중....
데몬 스레드가 실행중....
데몬 스레드가 실행중....
데몬 스레드가 실행중....
데몬 스레드가 실행중....
데몬 스레드가 실행중....
데몬 스레드가 실행중....
main thread 종료

대략 만들 수 있는 방식은 이정도일 것 같다.
만드는 방법만 다양해보이는 것이지 run()을 구현하는 것은 일맥상통하다.
run()이 아닌 start()를 이용해서 thread를 시작하는 것을 명심하자.

이외에 join과 wait, notify, setPriority 등의 메서드를 이용해서 순서를 보장하는 방식이 있다.
또한, synchronized 키워드를 통해서 한 순간에 한 스레드만 접근하도록 할 수 있다.
여기서는 기본 생성방식과 동작 원리만 다루도록 한다.


동작원리

동시성(Concurrency)

하나의 코어만 있을 때는 코어가 매우 빠른 속도로 Thread를 하나씩 돌아가며 처리한다.
1->2->3->1->2->3... 이런식으로 계속 돌아가면서 처리한다.

병렬성(Parallelism)

멀티 코어인 상태에서는 Thread를 한 번에 병렬로 처리한다.
1->1->1->...
2->2->2->...
3->3->3->...

Thread가 어떤 순서로 동작할지 결정하는 것을 '스케줄링'이라고 하는데
1. 우선순위를 정해서 어떤 것을 먼저 처리할지 정하는 방식과(코드레벨로 제어 가능)
2. 순환할당(Round Robin)방식으로 가상 기계에 의해 우선 순위를 두지 않고 일정 시간마다 돌아가면서 처리하는 방식이 있다.


출처
https://cornswrold.tistory.com/181
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Thread.html
https://wikidocs.net/230
https://honbabzone.com/java/java-thread/

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

Java 버전별 특징  (0) 2021.04.27
Stream  (0) 2021.04.27
Optional  (0) 2021.04.27
String, StringBuilder, StringBuffer  (0) 2021.04.21
GC(Garbage Collection)  (0) 2021.04.17