운영체제

스레드 생성

으엉어엉 2024. 11. 22. 12:13
728x90

자바 메모리 구조

 

메서드 영역(Method Area)  : 메서드 영역은 프로그램을 실행하는데 필요한 공통 데이터를 관리한다. 이 영역은 프로그램의 모든 영역에서 공유한다. 모든 실행코드. static, 공통 상수들.

 

스택 영역(Stack Area)  : 자바 실행 시, 하나의 실행 스택이 생성된다. 각 스택 프레임은 지역 변수, 중간 연산 결과, 메서드 호출 정보 등을 포함한다

 

힙 영역(Heap Area) : 객체(인스턴스)와 배열이 생성되는 영역이다. 가비지 컬렉션(GC)이 이루어지는 주요 영역이며, 더 이상 참조되지 않는 객체는 GC에 의해 제거된다.

 

스택 영역은 더 정확히는 각 스레드별로 하나의 실행 스택이 생성된다. 따라서 스레드 수만큼 스택이 생성된다. 지금은 스레드를 1개만 사용하므로 스택도 하나이다. 이후 스레드를 추가할 것인데, 그러면 스택도 스레드 수만큼 증가한다.

 

@Override
public void run() {
    System.out.println(Thread.currentThread().getName() + " is running");
}

 

Thread를 상속하고 실행 중인 스레드의 이름 조회한다.

` run()` 메서드가 아니라 반드시 ` start()` 메서드를 호출해야 한다.

 

 

실행 전:

실행 결과를 보면  main()  메서드는  main이라는 이름의 스레드가 실행하는 것을 확인할 수 있다. 프로세스가 작동하 려면 스레드가 최소한 하나는 있어야 한다.

 

실행 후:

HelloThread 스레드 객체를 생성한 다음에 start() 메서드를 호출하면 자바는 스레드를 위한 별도의 스택 공간을 할당한다.

스레드 객체를 생성하고, 반드시 start()를 호출해야 스택 공간을 할당 받고 스레드가 작동한다.

스레드에 이름을 주지 않으면 자바는 스레드에 Thread-0 ,1.... 이름이 임의로 부여된다.

 

 

 

main thread가 아닌 Thread-0이 run() 메서드를 실행한다. main은 단지 지시만 할 뿐이다.

 

스레드 간의 실행 순서는 얼마든지 달라질 수 있다.

CPU 코어가 2개여서 물리적으로 정말 동시에 실행될 수도 있고, 하나의 CPU 코어에 시간을 나누어 실행될 수도 있다. 그리고 한 스레드가 얼마나 오랜 기간 실행되는지도 보장하지 않는다. 한 스레드가 먼저 다 수행된 다음에 다른 스레드가 수행될 수도 있고, 둘이 완전히 번갈아 가면서 수행되는 경우도 있다. 스레드는 순서와 실행 기간을 모두 보장하지 않는다. 이것이 바로 멀티스레드다.

 

 

데몬 스레드

스레드는 사용자(user) 스레드와 데몬(daemon) 스레드 2가지 종류로 구분할 수 있다.

 

사용자 스레드(non-daemon 스레드)  : 프로그램의 주요 작업을 수행한다. 작업이 완료될 때까지 실행된다.

데몬 스레드 : 백그라운드에서 보조적인 작업을 수행한다. 모든 user 스레드가 종료되면 데몬 스레드는 자동으로 종료된다.

 

public class DaemonThreadMain {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + ": main() start");

        DaemonThread daemonThread = new DaemonThread();
        daemonThread.setDaemon(true); // 데몬 스레드 여부
        daemonThread.start();

        System.out.println(Thread.currentThread().getName() + ": main() end");
    }

    static class DaemonThread extends Thread {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + ": run() start");

            try {
                Thread.sleep(10000); // 10초간 실행
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            System.out.println(Thread.currentThread().getName() + ": run() end");
        }
    }
}

 

코드상으론 10초간 실행 되어야하지만 main에서 종료가 되었기에 같이 종료가 되어버린다.

 

스레드 생성 - Runnable

 

@Override
public void run() {
    System.out.println(Thread.currentThread().getName() + ": run()");
}
public static void main(String[] args) {
    System.out.println(Thread.currentThread().getName() + ": main() start");
    HelloRunnable runnable = new HelloRunnable();
    Thread thread = new Thread(runnable);
    thread.start();
    System.out.println(Thread.currentThread().getName() + ": main() end");
}

 

주로 실무에서 사용하는 방식

상속의 자유로움: 

Runnable 인터페이스 방식은 다른 클래스를 상속받아도 문제없이 구현할 수 있다.

코드의 분리:

스레드와 실행할 작업을 분리하여 코드의 가독성을 높일 수 있다. 여러 스레드가 동일한 Runnable객체를 공유할 수 있어 자원 관리를 효율적으로 할 수 있다

 

스레드와 실행할 작업을 명확히 분리하고, 인터페이 스를 사용하므로 Thread 클래스를 직접 상속하는 방식보다 더 유연하고 유지보수 하기 쉬운 코드를 만들 수 있다.

728x90

'운영체제' 카테고리의 다른 글

Thread 생명 주기 - 코드  (0) 2024.11.29
Thread 생명 주기 개념편  (0) 2024.11.29
컨텍스트 스위칭  (0) 2024.11.17
Thread - Scheduling,Thread  (0) 2024.11.17
Thread - process ,thread  (0) 2024.11.17