Computer Science/Operating System

Thread Pool(스레드 풀) / Monitor(모니터) / Fork-Join(포크-조인)

호준송 2023. 3. 8. 11:35
728x90
728x90

Thread를 단순하게 사용할 때 문제점

  1. 스레드는 생성 비용이 많이 든다.
    • 스레드를 생성할 때마다 Kernel 레벨의 스레드와 연결해야 한다.
    • Kernel의 작업이 필요하다.
  2. 스레드가 많아질수록 Context-Switching이 더 자주 발생하게 되어 CPU overhead가 증가한다.

→ Thread Pool을 사용하여 문제점을 해결한다.

 

 

Thread Pool


 

스레드를 허용된 개수 안에서 사용하도록 제한하는 시스템을 말한다.

  1. 스레드의 최대 개수를 제한하고 미리 생성한다.
  2. 사용자로부터 들어온 요청을 작업 큐에 넣는다.
  3. 작업 큐에 들어 있는 작업을 스레드 풀의 스레드가 맡아 처리한다.
  4. 작업이 끝난 스레드는 다시 3번 과정을 진행한다.

장점

  • 스레드를 재사용할 수 있기 때문에 새로운 스레드를 생성하는 비용을 줄일 수 있다.
  • 사용할 스레드의 개수를 제한하기 때문에 스레드가 무한정 생성되는 것을 방지할 수 있다.

단점

  • 최대 개수를 필요 이상의 개수로 설정하면 메모리 낭비가 발생한다.

사용 이유

  • 프로그램 성능저하를 방지할 수 있다.
  • 다수의 사용자 요청을 빠르게 처리하고 대응할 수 있다.

 

JAVA에서의 사용 및 최적화

  • ThreadPoolExecutor를 제공한다. (ExecuteService 상속)
    • maximumPoolSize : 최대 스레드의 개수
    • corePoolSize : 최소 필요한 스레드의 개수
    • keepAliveTime : 스레드 미사용 시 제거 대기 시간
  1. corePoolSize 만큼의 스레드로 시작한다.
  2. 남은 스레드가 없다면 스레드를 바로 추가하지 않고 작업큐가 다 찰 때 까지 큐에서 대기한다.
  3. 작업큐가 다 차면 스레드의 수를 늘린다.(최대 maximumPoolSize까지)
  4. keepAliveTime이 지나면 corePoolSize로 돌아간다.

 

 

Monitor(모니터)


 

세마포어에서 발전된 형태로, Mutual Exclusion을 지키기 위한 방식이다.

두 가지 큐를 사용한다.

  1. entry queue
    • critical section에 진입을 기다리는 큐
    • mutex에 의해 관리된다.
  2. waiting queue
    • 조건이 충족 되기를 기다리는 큐
    • condition variable 에 의해 관리된다.

장점

  • 사용하기 쉽다.
  • 오류 발생 가능성이 낮다.

단점

  • 지원하는 언어에서만 사용 가능하다.
  • 컴파일러가 OS를 이해하고 있어야 한다.

 

작동 방식

  1. mutex를 사용
    • acquire(m)에서 lock을 걸고 release(m)에서 lock을 해제한다.
    • lock이 걸려 있다면 다음 스레드는 entry queue에서 대기
  2. condition variable를 사용
    • wait(특정 조건이 충족될 때까지)
      • thread가 자기 자신을 condition variable의 waiting queue에 넣고 대기 상태로 전환
      • wait시 mutex lock을 풀고 entry queue에서 새로운 스레드가 모니터로 진입하며 lock을 건다.
      • 새로 들어온 스레드도 특정 조건이 충족되지 않으면 wait 하게 된다.
    • signal
      • waiting queue에서 대기중인 스레드 중 하나를 깨움
    • broadcast
      • waiting queue에서 대기중인 스레드를 전부 깨움

 

JAVA 에서의 사용

  • JAVA에서는 모든 객체가 내부적으로 monitor 를 가진다.
  • monitor 의 mutex 기능은 synchronized 키워드를 통해 사용한다.
  • monitor는 condition variable을 하나만 가진다.
  • 동작
    • wait
    • notify(= signal)
    • notifyAll(= broadcast)

 

 

Fork-Join


 

큰 작업을 여러 개의 작은 작업으로 나누고, 처리한 후 결과를 합치는 작업이다. ‘분할 정복’ 알고리즘의 병렬화 버전에 해당한다. 하나의 작업을 작은 단위로 나누어 여러 스레드가 동시에 처리할 수 있게 만든다.

  • fork() : 프로세스(작업)을 여러 개로 쪼개서 새롭개 생성하는 작업
  • join() : 포크해서 생성된 프로세스/스레드 의 결과를 합치는 작업
  • 순차 처리(fork-join을 사용하지 않은 경우)보다 무조건 빠른 것은 아니다.

 

Work Stealing(작업 훔치기)


fork-join 에서 스레드를 공정하게 분할하기 위한 방법이다.

  • 분할 기법이 효율적이지 않았거나, 외부 장애로 인해 스레드 별 작업속도에 차이가 생길 수 있다.
  • 한 스레드는 바쁘게 일하는 동시에 다른 스레드는 할 일이 없이 대기하는 상황이 생길 수 있다.
  • 각 스레드는 부모 큐에서 가져간 작업들을 내부 큐(inbound queue)에 담아 관리한다.
  • 스레드는 서로의 큐에 접근하여 작업을 가져올 수 있다.
  • 따라서, 쉬고 있는 큐가 바쁜 스레드의 큐에 가서 큐의 꼬리에 해당하는 작업을 빼앗아 오는 과정을 의미한다.

 

 

참고


[10분 테코톡] 조조그린의 Thread Pool

모니터가 어떻게 동기화에 사용되는지 아주 자세히 설명합니다! 자바에서 모니터는 어떤 모습인지도 설명하니 헷갈리시는 분들 꼭 보세요!

 

[Java] Fork Join Pool

Fork Join Pool의 상속구조 java.lang.Object java.util.concurrent.AbstractExecutorService java.util.concurrent.ForkJoinPool Fork Join Pool 이란? ForkJoinPool 은 Java7부터 사용가능한 Java Concurrency 툴이며, 동일한 작업을 여러개의

junghyungil.tistory.com

 

Fork/Join을 알아보자!

Fork AND JOIN

velog.io

 

[Java] 스레드 풀이란?

java-study에서 스터디를 진행하고 있습니다. 스레드 풀 개념 병렬 작업 처리가 많아지면 스레드 개수가 중가되고, 그에 따른 스레드 생성과 스케줄링으로 인해 CPU가 바빠져 메모리 사용량이 늘어

steady-coding.tistory.com

 

728x90
728x90