본문 바로가기
자바/자바 NIO

스레드의 구현, 멀티 스레드의 장점과 단점

by saul 2022. 7. 10.

스레드는 나에게 정말 어려운 부분이었다.  그래도 한번 정리해보고 싶어서 정리하게 되었다.

 

- 프로세스와 스레드의 차이

 

스레드(Thread) :

프로세스 내의 독립적인 순차 흐름 또는 제어, 경량 프로세스(Linght-weight Process)라고도 한다.

 

프로세스(Process) :

‘실행 중인 프로그램’.  프로그램을 실행하면 OS로부터 실행에 필요한 자원(메모리) 할당받아 프로세스가 된다.

 

하나의 프로세스가 가질 수 있는 스레드의 개수는 제한되어 있지 않으나 스레드가 작업을 수행하는데 개별적인 메모리 공간(호출 스택)을 필요로 하기 때문에 프로세스의 메모리 한계에 따라 생성할 수 있는 스레드의 수가 결정된다.

 

 

- 멀티 태스킹과 멀티 스레딩

 

멀티 태스킹 : 운영체제(OS)는 다중 작업, 멀티태스킹을 지원한다. 즉 한 운영체제에서 여러 가지의 프로그램을 동시에 사용할 수 있다. 이를 멀티태스킹으라고 한다. = 여러 가지의 프로세스가 동시에 실행될 수 있다.

 

멀티 스레딩 : 하나의 프로세스 내에서 여러 스레드가 동시에 작업을 수행하는 것이다.

하나의 CPU 코어가 한번에 하나의 스레드를 처리할 수 있으므로 컴퓨터에서 동시에 처리되는 스레드의 개수는 코어의 개수와 일치한다.

 

스프링 입문을 위한 자바 객체 지향의 원리와 이해에서 그림을 참조

 

위 그림에서 보듯이 스택 영역에 한 개 이상의 스레드들이 힙 영역과 스태틱 영역을 공유하는 것을 볼 수 있다. 

이는 각 스레드를 프로그램 내에서 적절히 제어함으로써 멀티 프로세스에 비해 좀 더 효율적인 스케줄 관리를 할 수 있다.

 

예)

편의점에서 물건을 살 때 카운터가 한 개가 있다면 한번에 한 손님만 계산해 줄 수 있다. 하지만 카운터가 때에 따라서 여러 개가 될 수 있다면 손님이 많아져도 효율적으로 손님이 가져온 물건을 계산해 줄 수 있다. 이와 같은 상황이 멀티 스레드이다. 하지만 편의점 매장의 크기는 한정적 이므로 카운터를 계속 늘릴 수는 없다. 마찬가지로 스레드를 무조건 많이 사용할 수는 없다.

 

한정된 자원을 생각해서 조절하면서 멀티 스레드를 사용해야 한다.

 

 

 

- 멀티 스레드의 장점과 단점

 

장점 :

* CPU의 사용률을 향상시킨다.

* 자원을 보다 효율적으로 사용할 수 있다.

* 사용자에 대한 응답성이 향상된다.

* 작업이 분리되어 코드가 간결해진다.  

 

단점 :

* 프로세스에게 할당되는 메모리(자원)는 제한적이다. 따라서 멀티 스레딩 프로세스라면 프로세스 내부의 스레드들이 자원을 공유하면서 작업해야 한다.

동기화 문제(synchronization)를 발생시키고, 더 나아가 하나의 스레드가 자원을 점유하고 있는 상황에서 다른 스레드가 점유한 자원을 사용하려고 기다리느라 진행이 멈추는 상태 즉, 교착상태(deadlock)와 같은 문제들을 발생시킬 수 있다.

 

스레드는 동시에 실행될 수 는 또 다른 실행 흐름을 갖게 함으로써 좀 더 효율적인 작업을 하게 해 주며 이렇게 병렬로 처리할 수 있어서 서버 프로그램의 대부분의 경우 애플리케이션의 성능과 효율을 향상시켜준다는 장점이 있다. 하지만 이에 따른 단점도 있다.

 

운영체제 시간에 배웠겠지만 CPU를 집중적으로 사용해야 하는 프로그램은 싱글 스레드 방식으로 진행하는 게 편하다. 여러 스레드를 사용하면 CPU스케쥴러에서 스레드를 여러 번 바꾸면서 실행하기 때문에 이는

문맥 교환 즉 시간 지연이 더 생긴다.

 

- 자바에서의 스레드 생명주기

 

Thread 인스턴스 생성하고 start () 메서드로 Thraed 인스턴스를 실행시킨다. 그러면 Runable 인터페이스를 구현한 객체 또는 Thread 클래스를 상속한 객체의 run() 메서드를 실행시킨다. 그 후 run() 메서드의 모든 처리가 끝나면 바로 해당 Thraed 인스턴스가 소멸된다.

 

 

- 자바에서의 스레드 생성 방법

 

1) white-box, Thread 클래스 상속

스레드 구현의 첫 번째 방법은 상속을 이용하는 것이다. 자바에서 이미 구현되어 있는 Thread 클래스를 상속하고 비즈니스 로직이 들어갈 run() 메서드만 오버 라이딩해서 재정의 해주면 된다.

Thread 클래스를 상속 받았다.
상속 받은 후 start() 메소드를 통해 실행

2) black-box, Runnable 인터페이스 구현

스레드 구현의 또 다른 방법은 합성을 이용하는 것이다. Runable 인터페이스를 구현하는 클래스를 만들고

새로운 Thread 객체를 생성할 때, 앞서 구현한 클래스를 객체의 형태로 스레드 객체에 파라미터로 넘기는 방식이다. 이를 객체 합성이라고 한다.

 

 

 

 

- 상속 vs 합성

 

과연 두 가지 방법 중에서 어떤 방법이 더 나은 방법일까?

객체지향 시스템에서의 기능의 재사용을 위한 가장 대표적인 두 가지 방법이 상속과 합성이다.

 

디자인 패턴에서는 상속을 통한 재사용을 white-box reuse라고 하고,

객체 합성을 통한 방법을 black-box reuse라고 한다. 왜 이런 식으로 부르는 걸까?

 

먼저, 상속부터 먼저 생각해 보자. 어떤 클래스를 상속하면 private으로 선언되지 않은 모든 변수와 메서드, 생성자가 하위 클래스에 노출된다. 이렇게 하위 클래스에서 슈퍼 클래스의 내부가 보인다는 의미로 White - box reuse라고 한다. 투명한 하얀색 상자 안에 어떤 것이 있는지 밖에서 본다면 잘 볼 수 있을 것이다.

 

상속의 장점은 슈퍼 클래스에게 접근을 쉽게 할 수 있고, 오버라이딩을 통해 알맞은 내용으로 변환하기도 쉽다는 것이다. 그럼에도 불구하고 상속을 이용해서 재사용할 때, 시스템 설계자들은 무엇을 못마땅하게 여기는 것일까?

 

슈퍼클래스 하위 클래스에 불필요하게 많은 부분이 노출된다는 것이다. 이는 객체지향의 원칙 중 하나인 캡슐화에 위배되고 또한 하위 클래스가 상위 클래스의 구현에 종속되고, 상위 클래스 구현이 변경되어야 할 경우가 생기면 하위 클래스도 변경해야 하는 문제점이 생길 수 있다.

 

또한 시간이 지남에 따라 시스템의 진화도 자동으로 이뤄진다. (라이브러리는 시간이 지날수록 새로운 기능이 추가되고 버그 수정을 위해 변경된다) 시스템이 진화를 할수록 상속 관계가 복잡해져서 그 시스템의 상속 트리를 정확하게 이해하고 있지 않으면 시스템의 수정과 확장에 손을 댈 수 없는 상황까지 발생한다.

 

이처럼 상속에는 단점과 장점이 존재하기 때문에 사용방법을 잘 숙지하고 사용해야 한다.

또한 black-box 방법이 캡슐화와 확장성 유연성 면에서 더 나을 것이다.

 

객체 합성은 객체가 다른 객체의 참조자를 얻는 방식으로 런타임 시에 동적으로 이루어진다.

다른 객체의 참조자를 얻은 후 그 참조자를 사용해서 객체의 기능을 이용하기 때문에 해당 객체의 인터페이스 (public 메서드들. 캡슐화에서는 public 메서드만으로만 필드에 접근이 가능하게 만드는 것이 정석이다.)만을 바라보게 됨으로써 더 캡슐화가 잘 이뤄질 수 있다. 즉 해당 객체에서 공개하는 것들만 볼 수 있고 이용할 수 있다는 것이다. 이렇게 각 객체의 캡슐화를 유지할 수 있기 때문에 시스템 설계자들이 상속보다 합성을 더 선호하는 것이다.

 

또한 객체 합성이 객체 서로의 내부를 볼 수 없기 때문에 black-box라고 말한다.

즉 그 내부가 비치지 않아 밖에서 박스 안을 볼 수 없다는 것이다.

 

하지만 합성에도 오용에 따른 단점과 주의점이 있다. 우선 객체 합성은 객체 간의 관계가 수직 관계가 아닌 수평관계가 된다는 것이다. 따라서 큰 시스템에서 많은 부분에 걸쳐 합성이 사용될 때 객체나 메서드 명이 명확하지 않으면 코드의 가독성이 떨어지고 이해하기 어려워진다.

 

따라서 합성을 하는 경우에는 그 용도에 따라 클래스들을 잘 분리하고 각각의 사용용도를 명확하게 드러나도록 인터페이스를 잘 설계해야 한다.

 

 

 

 

 

 

 

 

 

참고 :

김성박, 송지훈 『자바 I/O&NIO 네트워크 프로그래밍

『JAVA의 정석』 스레드 파트

스프링 입문을 위한 자바 객체 지향의 원리와 이해

'자바 > 자바 NIO' 카테고리의 다른 글

스레드 구현(추가)과 실행  (1) 2022.07.10
TCP프로토콜과 소켓, 포트  (4) 2022.06.30
기초 네트워크  (2) 2022.06.29