Language/Java

쓰레드(Thread)의 기본개념

이웃비 2022. 5. 10. 19:58
프로그램과 프로세스

우리가 프로그램을 실행하려고 하면, 실행을 위해 운영체제에서 메모리 공간을 할당받아오게 되며, 그 공간에 프로그램이 올려져 실행되게 된다. 즉 프로세스는 실행중인 프로그램, 혹은 그 작업이라고 할 수 있다.

간단히 말해

프로그램은 저장장치에 저장되어있는 정적인 상태이고,

프로세스는 실행을 위해 메모리에 올라와있는 동적인 상태이다.

 

프로세스의 상태에는 5가지가 존재한다.

  • 생성 상태(create status) : 프로세스가 메모리에 올라와 실행 준비를 완료한 상태
  • 준비 상태(ready status) : 생성된 프로세스가 CPU를 얻을 때까지 기다리는 상태
  • 실행 상태(running status, execute status) : 준비 상태에 있던 프로세스 중 하나가 CPU를 얻어 실제 작업을 수행하는 상태. 실행 상태에 들어간 프로세스는 일정 시간 CPU를 사용할 권리를 얻는다. 주어진 시간안에 작업을 다 처리하지 못했다면 다시 준비 상태(ready status)로 돌아와 다음 차례를 기다리게 된다.
  • 완료 상태(terminate status) : 실행 상태의 프로세스가 주어진 시간 동안 작업을 마치면 완료 상태로 진입한다.
  • 대기 상태(blocking status) : 실행 상태에 있는 프로세스가 입출력을 요청하면 입출력을 완료할때까지는 기다리는 상태. 입출력이 완료되면 준비상태로 돌아간다.

* 인터럽트(interrupt) : CPU는 입출력 관계자에게 작업 지시를 내리고 다른 일을 하다가 완료 신호를 받으면 하던 일을 중단하고 옮겨진 데이터를 처리한다. 하던 일을 중단하고 처리해야 하는 신호라서 인터럽트라고 불리게 되었다.

 

스레드(THREAD)

그렇다면 스레드는 무엇일까?

스레드는 CPU에 작업 요청을 하는 실행단위를 말한다.

운영체제는 프로그램을 실행시키기 위해 프로그램의 코드와 데이터를 메모리에서 가져오고, 프로세스 제어 블록(PCB)을 생성하고, 작업에 필요한 메모리를 확보한 후, 준비된 프로세스를 준비 큐에 삽입한다.

이렇게 프로세스가 생성되면 CPU스케줄러는 CPU에게 해야 하는 일을 전달하고, CPU가 그 일을 하게 된다. 이때 CPU가 받는 일을 스레드라고 한다.

결국 운영체제 입장에서 작업의 단위는 프로세스지만,

CPU입장에서는 스레드가 되는 것이다.

 

프로세스(PROCESS)와 스레드(THREAD)의 차이

프로세스와 스레드의 차이를 이해하기 위해, 한가지 가정을 해보겠다.

만약 오늘 내가 할 일이 밥 먹기, 공부하기, 운동하기 라고 가정해 보자.

오늘 밥을 못 먹었다고, 공부할 수 없는 것이 아니다. 운동을 못해도 공부는 할 수 있으며, 공부를 못해도 밥은 먹을 수 있다. 각각 서로 다른 일인 것이다.

하지만 점심을 먹기 위해 해야하는 순서인 1. 밥 짓기 2. 반찬 준비하기 3. 수저놓기 중 하나를 하지 못했다면 밥 먹기라는 일을 수행 할 수 없다.

이때 밥먹기, 공부하기 같은 일은 프로세스에 해당이 되고, 밥을 먹기 위한 식사 차리는 작업은 스레드에 해당된다.

또한 점심을 먹기 위한 작업인 밥 짓기, 반찬 준비하기 등 점심시간 내 여러가지일을 동시에 처리하는 것을 멀티스레드라고 한다. 

결국 프로세스와 스레드의 가장 큰 차이점은 독립성이다. 각각의 프로세스는 다른 프로세스에 영향을 미치지 않지만, 스레드의 작업은 다른 스레드에 영향을 미칠 수 있다.

 

자바에서의 스레드

JAVA 프로그램은 JVM이 운영체제 위에서 작동하며 운영체제로부터 자원을 할당받아 프로그램을 실행하게 된다.

JVM이 프로그램 시작점인 main() 메서드를 찾아 메인 스레드를 생성하고 메인 스레드의 run()메서드를 통해 해당 main()메서드를 실행한다.

우리가 흔히 처음 프로젝트를 시작할 때 쓰는 public static void main(String[] args) { 을 통해 메인 스레드가 시작되게 되는 것이다.

이 시점에서 스레드는 메인 스레드 하나이기에 싱글 스레드라고 부를 수 있다.

참고로 JVM시작시 데몬스레드도 시작되게 되는데, 로직을 실행하는 스레드는 메인스레드 하나이기 때문에 싱글 스레드라고 부른다.

참고로 데몬스레드는 다른 스레드에 도움을 주는 스레드로, 대표적으로 가비지컬렉터가 있다. 메인스레드가 종료되면 데몬 스레드도 같이 종료된다.

아무튼 메인메소드는 main()메소드를 통해 실행되면 마지막 코드가 실행되거나 return문을 만나면 종료되게 된다.

이런 싱글 스레드 애플리케이션에서는 메인 스레드가 종료되면 프로세스도 그대로 종료되고 만다. 그러나 멀티스레드 애플리케이션에서는 실행중인 스레드가 하나라도 있으면 프로세스는 종료되지 않는다. 특히, 메인스레드가 작업 스레드보다 먼저 종료되어도 작업 스레드가 실행중이라면 프로세스는 종료되지 않는다.

 

왜 스레드를 사용하는가?

그렇다면 왜 멀티 프로세스를 사용하는게 아닌, 멀티 스레드를 사용하는가?

이는 메모리 절약을 위해서다

OS마다 다르지만, 무슨 작업을 수행하려고 할 때 적어도 32~64mb 물리메모리를 점유하게 된다고 한다. 그러나 스레드는 1MB 이내의 메모리만 점유한다. 그래서 스레드를 경량 프로세스라고도 부른다.

스레드는 어떻게 메모리를 적게 점유할수 있는 걸까?

스레드는 이처럼 생성될 때마다 스택이 새롭게 생성될 뿐 프로세스 내에서 힙,데이터를 공유하기 때문에 프로세스 콘텍스트 스위칭(Context Switching)에 비해 오버헤드를 절감한다.

* 콘텍스트 스위칭 : 스케줄러가 기존 실행 프로세스를 우선순위 때문에 미루고 새 프로세스로 교체해야 할 때 프로세스 상태 값을 교체하는 작업

 


참고자료

https://boomrabbit.tistory.com/131

https://dololak.tistory.com/15

https://beststar-1.tistory.com/6