JAVA

스레드(Thread)

yujin0517 2024. 1. 27. 16:25

목차

스레드란?

스레드 고안

스레드 이점

스레드 사용의 위험성

 

스레드는 멀티프로세서 시스템의 능력을 최대한 끌어낼 수 있는 가장 쉬운 방법이다. 프로세서 개수가 늘어날수록 여러 작업을 동시에 실행하는 일이 더욱 중요하다. 

 


스레드란(Thread)?

스레드란 프로세스 내에서 실제로 작업을 수행하는 주체를 의미하며, 스레드 사용으로 인해 하나의 프로그램 안에 여러 개의 프로그램 제어 흐름이 공존할 수 있다. 모든 프로세스에는 한 개 이상의 스레드가 존재하여 작업을 수행한다.

  • 프로세스(Process)란?

      → 프로세스란 운영체제에 의해 메모리에 적재되어 실행 중인 프로그램이다. 프로세스는 독립적인 메모리 영역을 사용한다. 

 


스레드 고안

스레드는 프로세스의 문제점을 해결하고자 고안됐다. 프로세스의 생성 및 소멸에 따른 오버 헤드를 감소하고, 컨텍스트 스위칭을 빠르게 진행하고, 프로세스의 복잡한 통신 방법과 느린 실행 속도를 개선하고자 스레드가 만들어 졌다. 

또한, 자원 활용, 공정성, 편의성 등의 프로세스 개념을 만들어내게 된 것과 같은 동기를 가지고 스레드가 고안됐다. 스레드로 인해 한 프로세스 안에 여러 개의 프로그램 제어 흐름이 공존할 수 있다. 스레드는 프로세스에 할당된 자원을 공유한다. 각 스레드는 각자 별도의 프로그램 카운터, 스택, 지역 변수를 갖는다. 또한, 프로그램을 스레드로 분리하면 멀티프로세서 시스템에서 자연스럽게 하드웨어 병렬성을 이용할 수 있다. 즉, 하나의 프로그램 내에서 여러 스레드를 동시에 여러 개의 CPU에 할당해 실행할 수 있다. 

하나의 스레드는 다른 스레드와 상관없이 비동기적으로 실행된다. 스레드는 자신이 포함된 프로세스의 메모리 주소 공간을 공유하기 때문에 한 프로세스 내 모든 스레드는 같은 변수에 접근하고 같은 힙에 객체를 할당한다. 때문에 프로세스 보다 더 세밀한 단위로 데이터를 공유할 수 있다. 하지만 공유된 데이터에 접근하는 과정을 적절하게 동기화하지 않으면 다른 스레드가 사용중인 변수를 순간적으로 수정해서 예상치 못한 결과를 얻을 수도 있다. 

 


스레드 이점

스레더를 사용하면 개발 및 유지 보수 비용을 절약할 수 있고, 복잡한 애플리케이션의 성능을 향상시킬 수 있다. 

  • 멀티 프로세서 활용

여러 개의 스레드를 사용하면 프로세서가 하나라도 처리 속도를 높일 수 있다. 프로그램이 스레드 하나로 구성되어 있다면 동기 I/O 작업이 완료될 때 까지 기다리는 동안 프로세서가 놀게된다. 하지만 멀티스레드 프로그램에서는 스레드 하나가 I/O가 끝나길 기다리는 동안 다른 스레드가 계속 실행될 수 있다. 즉, I/O 때문에 대기 상태에 들어가는 동안에도 다른 스레드는 동작할 수 있기 때문에 애플리케이션이 계속 실행된다. 

  • 단순한 모델링

한 종류의 일을 순차적으로 처리하는 프로그램은 작성하기 쉽고 오류도 많이 생기지 않는다. 여러 종류의 일을 동시에 처리하는 프로그램보다 테스트하기도 쉽다. 

종류별 작업마다 또는 시뮬레이션 작업의 각 요소마다 스레드를 하나씩 할당하면 마치 순차적인 작업처럼 처리할 수 있고 스케줄링, 교차 실행되는 작업, 비동기 I/O, 자원 대기 등의 세부적인 부분과 상위의 비즈니스 로직에 해당하는 부분을 분리할 수 있다. 즉, 복잡하면서 비동기적인 작업 흐름을 별도의 스레드에서 수행되는 더 단순하고 동기적인 작업 흐름으로 나눌 수 있다. 

예를 들어, 웹 요청이 들어와서 서블릿의 service 메서드가 호출될 때, 해당 요청을 마치 단일 스레드 프로그램인 것처럼 처리할 수 있다. 때문에 컴포넌트 개발 작업이 훨씬 단순해지고 프레임워크를 쉽게 익힐 수 있다. 

  • 단순한 비동기 이벤트 처리 

스레드가 하나 뿐이고, 읽을 데이터가 없는 소켓에서 데이터를 읽으려고 하면 애플리케이션에 추가 데이터가 들어올 때 까지 read 연산에서 대기해야 한다. 이렇게 되면 해당 요청에 대한 작업이 멈출뿐만 아니라 다른 요청도 처리하지 못한다. 이 때, 각 요청을 별개 스레드에서 처리하면 대기 상태에 들어가도 다른 스레드가 요청을 처리하는데는 영향을 끼치지 않는다. 

하나의 프로세스가 생성할 수 있는 스레드 개수에 제한이 있기 때문에, 운영체제에서는 유닉스 시스템의 select나 poll 시스템 콜처럼 효율적인 다중화 I/O 수단을 개발했고, 표준 자바 API에도 대기 상태에 들어가지 않는 I/O를 지원할 수 있도록 java.nio와 같은 패키지를 추가했다. 이후 운영체제에서 더 많은 스레드를 지원할 수 있게됨으로써 일부 플랫폼에서는 다수의 클라이언트에 대해 클라이언트마다 스레드를 하나씩 생성할 수 있다. 

 


스레드 사용의 위험성

  • 안전성 위험

멀티 스레드 환경에서 동기화되지 않은 코드를 실행할 경우 결과를 예측하기 어렵다. 만약 연산이 단일 연산이 아닌 복합 연산이라면, 서로 다른 스레드가 동시에 같은 값을 읽고 연산을 수행해 원하는 결과를 얻지 못 할 수도 있다. 

  • 활동성 위험

스레드의 안전성은 단일 스레드 프로그램과 멀티 스레드 프로그램 모두에게 중요하다. 멀티 스레드를 사용하면 단일 스레드를 사용할 때는 발생하지 않는 추가적인 안전성 위험에 노출될 수도 있다. 또한, 단일 스레드를 사용할 때는 나타나지 않는 활동성 장애가 발생할 수 있다. 어떤 작업이 전혀 진전되지 못하는 상태에 빠질 수 있다는 말이다. 

예를 들어, 스레드 A에서 스레드 B가 독점하고 있는 자원을 기다리고 있는데 스레드 B가 해당 자원을 절대 놓아주지 않는다면 스레드 A는 계속 기다리기만 해야 한다. 활동성 장애의 종류에는 데드락(deadlock), 소모 상태(starvation), 라이브락(livelock) 등이 있다. 활동성 장애는 개발이나 테스트 도중에 잘 들어나지 않기 때문에 초기에 파악하기 어렵다. 

  • 성능 위험

스레드를 사용하면 어느 정도 부하가 생길 수 있다. 스레드가 많은 프로그램에서는 컨텍스트 스위칭이 더 빈번하게 발생한다. 때문에 실행 중인 컨텍스트를 저장하고 다시 읽으면서 메모리를 읽고 쓰는 지역성이 손실되고, 스레드를 실행하기도 버거운 CPU 시간을 스케줄링하는데 소모해야 한다. 

또, 스레드가 데이터를 공유할 때는 동기화 방법을 사용해야 하는데, 동기화는 컴파일러 최적화를 방해하고, 메모리 캐시를 지우거나 무효화 하기도 한다. 

 

이 글은 '자바 병렬 프로그래밍' 1장 내용을 참고하여 정리한 글 입니다. 

'JAVA' 카테고리의 다른 글

JSP와 서블릿(Servlet) 그리고 MVC 패턴  (1) 2024.02.06
스레드 풀(Thread Pool)과 Executor  (0) 2024.01.31
소수 찾기, 구하기  (0) 2023.02.01
[Java] 다형성(polymorphism)  (0) 2022.08.31
[Java] 추상 클래스(abstract)  (0) 2022.08.19