자바 메모리 구조 복습

- 메서드 영역(Method Area): 메서드 영역은 프로그램을 실행하는데 필요한 공통 데이터를 관리한다. 이 영역은 프로그램의 모든 영역에서 공유한다.
- 클래스 정보: 클래스의 실행 코드(바이트 코드), 필드, 메서드와 생성자 코드등 모든 실행 코드가 존재한다.
- static 영역: static 변수들을 보관한다.
- 런타임 상수 풀: 프로그램을 실행하는데 필요한 공통 리터럴 상수를 보관한다.
- 스택 영역(Stack Area) : 자바 실행 시, 하나의 실행 스택이 생성된다. 각 스택 프레임은 지역 변수, 중간 연산 결 과, 메서드 호출 정보 등을 포함한다.
- 스택 프레임: 스택 영역에 쌓이는 네모 박스가 하나의 스택 프레임이다. 메서드를 호출할 때 마다 하나의 스택 프레임이 쌓이고, 메서드가 종료되면 해당 스택 프레임이 제거된다.
- 힙 영역(Heap Area) : 객체(인스턴스)와 배열이 생성되는 영역이다. 가비지 컬렉션(GC)이 이루어지는 주요 영 역이며, 더 이상 참조되지 않는 객체는 GC에 의해 제거된다.
참고
: 스택 영역은 더 정확히는 각 스레드별로 하나의 실행 스택이 생성된다. 따라서 스레드 수 만큼 스택이 생성 된다. 지금은 스레드를 1개만 사용하므로 스택도 하나이다. 이후 스레드를 추가할 것인데, 그러면 스택도 스레드 수 만큼 증가한다.
스레드 생성
스레드를 만들 때는 Thread 클래스를 상속 받는 방법과 `Runnable` 인터페이스를 구현하는 방법이 있다. 먼저 Thread 클래스를 상속 받아서 스레드를 생성해보자
자바는 많은 것을 객체로 다룬다. 자바가 예외를 객체로 다루듯이, 스레드도 객체로 다룬다. 스레드가 필요하면, 스레드 객체를 생성해서 사용하면 된다

- Thread 클래스를 상속하고, 스레드가 실행할 코드를 run() 메서드에 재정의한다.
- Thread.currentThread() 를 호출하면 해당 코드를 실행하는 스레드 객체를 조회할 수 있다.
- Thread.currentThread().getName() : 실행 중인 스레드의 이름을 조회한다.

- 앞서 만든 HelloThread 스레드 객체를 생성하고 start() 메서드를 호출한다.
- start() 메서드는 스레드를 실행하는 아주 특별한 메서드이다.
- start() 를 호출하면 HelloThread 스레드가 run() 메서드를 실행한다.
주의: run() 메서드가 아니라 반드시 start() 메서드를 호출해야 한다. 그래야 별도의 스레드에서 run() 코드가 실행된다.
스레드 동작 과정

- 실행 결과를 보면 main() 메서드는 main 이라는 이름의 스레드가 실행하는 것을 확인할 수 있다. 프로세스가 작동하 려면 스레드가 최소한 하나는 있어야 한다. 그래야 코드를 실행할 수 있다. 자바는 실행 시점에 main 이라는 이름의 스레드를 만들고 프로그램의 시작점인 main() 메서드를 실행한다.

- HelloThread 스레드 객체를 생성한 다음에 start() 메서드를 호출하면 자바는 스레드를 위한 별도의 스택 공간을 할당한다
- 스레드 객체를 생성하고, 반드시 start() 를 호출해야 스택 공간을 할당 받고 스레드가 작동한다.
- 스레드에 이름을 주지 않으면 자바는 스레드에 Thread-0 , Thread-1 과 같은 임의의 이름을 부여한다. 새로운 Thread-0 스레드가 사용할 전용 스택 공간이 마련되었다.
- Thread-0 스레드는 run() 메서드의 스택 프레임을 스택에 올리면서 run() 메서드를 시작한다.
메서드를 실행하면 스택 위에 스택 프레임이 쌓인다
- main 스레드는 `main()` 메서드의 스택 프레임을 스택에 올리면서 시작한다.
-
직접 만드는 스레드는 run() 메서드의 스택 프레임을 스택에 올리면서 시작한다.

- main 스레드가 HelloThread 인스턴스를 생성한다. 이때 스레드에 이름을 부여하지 않으면 자바가 Thread-0 , Thread-1 과 같은 임의의 이름을 부여한다.
- start() 메서드를 호출하면, Thread-0 스레드가 시작되면서 Thread-0 스레드가 run() 메서드를 호출한다.
- 여기서 핵심은 main 스레드가 run() 메서드를 실행하는게 아니라 Thread-0 스레드가 run() 메서드를 실행한다는 점이다.
- main 스레드는 단지 start() 메서드를 통해 Thread-0 스레드에게 실행을 지시할 뿐이다. 다시 강조하지만 main 스레드가 run() 을 호출하는 것이 아니다! main 스레드는 다른 스레드에게 일을 시작하라고 지시만 하고, 바로 start() 메서드를 빠져나온다.
- 이제 main 스레드와 Thread-0 스레드는 동시에 실행된다.
- main 스레드 입장에서 보면 그림의 1, 2, 3번 코드를 멈추지 않고 계속 수행한다. 그리고 run() 메서드는 main 이 아닌 별도의 스레드에서 실행된다.
스레드 간 실행 순서는 보장하지 않는다.
스레드 간의 실행 순서는 얼마든지 달라질 수 있다. CPU 코어가 2개여서 물리적으로 정말 동시에 실행될 수도 있고, 하나의 CPU 코어에 시간을 나누어 실행될 수도 있다.
그리고 한 스레드가 얼마나 오랜기간 실행되는지도 보장하지 않는다. 한 스레드가 먼저 다 수행된 다음에 다른 스레드가 수행될 수도 있고, 둘이 완전히 번갈아 가면서 수행되는 경우도 있다.
스레드는 순서와 실행 기간을 모두 보장하지 않는다. 이것이 바로 멀티스레드다!
Start() VS Run()
스레드의 start() 대신에 재정의한 run() 메서드를 직접 호출하면 어떻게 될까?


실행 Flow

- 실행 결과를 잘 보면 별도의 스레드가 run() 을 실행하는 것이 아니라, main 스레드가 run() 메서드를 호출 할 것을 확인할 수 있다.
- 자바를 처음 실행하면 `main` 스레드가 `main()` 메서드를 호출하면서 시작한다.
- main 스레드는 HelloThread 인스턴스에 있는 run() 이라는 메서드를 호출한다.
- main 스레드가 run() 메서드를 실행했기 때문에 main 스레드가 사용하는 스택위에 run() 스택 프레임이 올라간다.

- 결과적으로 main 스레드에서 모든 것을 처리한 것이 된다.
- 스레드의 start() 메서드는 스레드에 스택 공간을 할당하면서 스레드를 시작하는 아주 특별한 메서드이다. 그리고 해당 스레드에서 run() 메서드를 실행한다. 따라서 main 스레드가 아닌 별도의 스레드에서 재정의한 run() 메서 드를 실행하려면, 반드시 start() 메서드를 호출해야 한다.
'멀티스레드와 동시성' 카테고리의 다른 글
| Ch02. 스레드 생성과 실행 - 스레드 생성(Runnable) (0) | 2024.08.01 |
|---|---|
| Ch02. 스레드 생성과 실행 - 데몬 스레드 (0) | 2024.08.01 |
| Ch01. 프로세스와 스레드 소개 - 스레드와 스케줄링 (0) | 2024.07.22 |
| Ch01. 프로세스와 스레드 소개 - 프로세스와 스레드 (0) | 2024.07.17 |
| Ch01. 프로세스와 스레드 소개 - 멀티 Tasking과 멀티 Processing (0) | 2024.07.17 |